Day1.实现内置类型
1.首字母大写 CapitalizeString
// 实现
// type CapitalizeString<T> = T extends `${infer R}${infer K}` ? `${Uppercase<R>}${K}` : T
type CapitalizeString<T extends string | number> = T extends string ? Capitalize<T> : T
// 使用
type a1 = CapitalizeString<'handler'> // Handler
type a2 = CapitalizeString<'parent'> // Parent
type a3 = CapitalizeString<233> // 233
// 测试
let s1: a1 = 'Handler'
let s2: a2 = 'Parent'
let s3: a3 = 233
2.获取字符串字面量中的第一个字符 FirstChar
// 实现
type FirstChar<T> = T extends `${infer E}${infer _S}` ? E : never
// 使用
type A = FirstChar<'BFE'> // 'B'
type B = FirstChar<'dev'> // 'd'
type C = FirstChar<''> // never
// 测试
let s1: A = 'B'
let s2: B = 'd'
function f(): C {
throw new Error('报错')
}
3.获取字符串字面量中的最后一个字符 LastChar
用数组存储, 最后拿数组最后一位
// 实现
type LastChar<T extends string, A extends string[] = []> = T extends `${infer S}${infer U}`
? LastChar<U, [...A, S]>
: A extends [...infer _L, infer R]
? R
: never
// 使用
type A = LastChar<'BFE'> // 'E'
type B = LastChar<'dev'> // 'v'
type C = LastChar<''> // never
// 测试
let s1: A = 'E'
let s2: B = 'v'
function f(): C {
throw new Error('报错')
}
4.字符串转换为元组类型 StringToTuple
// 实现
type StringToTuple<T extends string, A extends string[] = []> = T extends
`${infer S}${infer U}`
? StringToTuple<U, [...A, S]>
: A
// 使用
type A = StringToTuple<'BFE.dev'> // ['B', 'F', 'E', '.', 'd', 'e','v']
type B = StringToTuple<''> // []
// 测试
let tuple1: A = ['B', 'F', 'E', '.', 'd', 'e', 'v']
let tuple2: B = []
5.将字符串类型的元素转换为字符串字面量类型 TupleToString
// 实现
type TupleToString<T, S extends string = ''> = T extends [infer L, ...infer R]
? L extends `${infer LL}` ? TupleToString<R, `${S}${LL}`> : ''
: S
// 使用
type A = TupleToString<['a', 'b', 'c']> // 'abc'
type B = TupleToString<[]> // ''
type C = TupleToString<['a']> // 'a'
// 测试
let s1: A = 'abc'
let s2: B = ''
let s3: C = 'a'
6.复制字符T为字符串类型,长度为C RepeatString<T,C>
// 实现 [利用length记录递归次数]
type RepeatString<
T extends string,
N extends number,
S extends string = '',
A extends any[] = []
> = A['length'] extends N
? S
: RepeatString<T, N, `${S}${T}`, [1, ...A]>
// 使用
type A = RepeatString<'a', 3> // 'aaa'
type B = RepeatString<'a', 0> // ''
// 测试
let s1: A = 'aaa'
let s2: B = ''
7.将字符串字面量类型按照指定字符,分割为元组。 SplitString
// 实现
type SplitString<
T extends string,
S extends string,
A extends any[] = []
> = T extends ""
? []
: T extends `${infer L}${S}${infer R}`
? SplitString<R, S, [...A, L]>
: [...A, T]
// 使用
type A1 = SplitString<'handle-open-flag', '-'> // ["handle", "open", "flag"]
type A2 = SplitString<'handle.open.flag1', '.'> // ["handle", "open", "flag1"]
type A3 = SplitString<'open.flag', '-'> // ["open.flag"]
// 测试
let a1: A1 = ["handle", "open", "flag"]
let a2: A2 = ["handle", "open", "flag1"]
let a3: A3 = ["open.flag"]
8.计算字符串字面量类型的长度 LengthOfString
// 实现
type LengthOfString<
T,
A extends any[] = []
> = T extends `${infer L}${infer R}`
? LengthOfString<R, [...A, L]>
: A['length']
// 使用
type A = LengthOfString<'BFE.dev'> // 7
type B = LengthOfString<''> // 0
// 测试
let s1: A = 7
let s2: B = 0
9.驼峰命名转横杠命名 KebabCase
// 实现
// 使用三个类型实现
type KebabCaseIterator<
T extends string,
A extends any[] = []
> = T extends ""
? A
: T extends `${infer L}${infer R}`
? KebabCaseIterator<R, [...A, L extends Uppercase<L> ? `-${Lowercase<L>}` : L]>
: never
type joinString<T> = T extends [infer L, ...infer R]
? L extends string
? `${L}${joinString<R>}`
: never
: ""
type removeFirstSeparator<T> = T extends `-${infer S}` ? S : T
type KebabCase<T extends string> = removeFirstSeparator<
joinString<
KebabCaseIterator<T>
>
>
// 使用
type A = KebabCase<'HandleOpenFlag'> // handle-open-flag
type B = KebabCase<'OpenFlag'> // open-flag
// 测试
let s1: A = "handle-open-flag"
let s2: B = "open-flag"
10.横杠命名转化为驼峰命名 CamelCase
// 实现
type CamelCase<T> = JoinArray<SplitString<T, '-'> >
type SplitString<
T,
Separator extends string,
A extends any[] = []
> = T extends `${infer L}${Separator}${infer R}`
? SplitString<R, Separator, [...A, L]>
: [...A, T]
type JoinArray<T, S extends string = ''> = T extends [infer L, ...infer R]
? L extends string
? JoinArray<R, `${S}${Capitalize<L>}`>
: S
: S
// 使用
type A = CamelCase<"handle-open-flag">; // HandleOpenFlag
type B = CamelCase<"open-flag">; // OpenFlag
// 测试
let s1: A = "HandleOpenFlag"
let s2: B = "OpenFlag"
11.字符串拼接 JoinString
// 实现
type JoinString<
T extends string,
K extends string,
Separator extends string
> = T extends ""
? K extends ""
? never
: K
: K extends ""
? T
: `${T}${Separator}${K}`
// 使用
type S1 = JoinString<"top", "title", ".">; // top.title
type S2 = JoinString<"", "title", ".">; // title
type S3 = JoinString<"top", "", ".">; // top
type S4 = JoinString<"", "", ".">; // never
// 测试
let s1: S1 = "top.title"
let s2: S2 = "title"
let s3: S3 = "top"
function s4(): S4 {
throw new Error('ccc')
}
11.得到对象中的值访问字符串 ObjectAccessPaths
// 简单来说,就是根据如下对象类型:
/*
{
home: {
topBar: {
title: '顶部标题',
welcome: '欢迎登录'
},
bottomBar: {
notes: 'XXX备案,归XXX所有',
},
},
login: {
username: '用户名',
password: '密码'
}
}
*/
// 得到联合类型:
/*
home.topBar.title | home.topBar.welcome | home.bottomBar.notes | login.username | login.password
*/
// 实现
type JoinString<
T extends string,
K extends string,
Separator extends string
> = T extends ""
? K extends ""
? never
: K
: K extends ""
? T
: `${T}${Separator}${K}`
type ObjectAccessPaths<
T extends Record<string, any>,
Pre extends string = '',
K = keyof T
> =
K extends keyof T
? K extends string
? T[K] extends Record<string, any>
? ObjectAccessPaths<T[K], JoinString<Pre, K, '.'>>
: JoinString<Pre, K, '.'>
: never
: never
// 使用
function createI18n<T>(obj: T): (path: ObjectAccessPaths<T>) => string {
return (path) => ''
}
const i18n = createI18n({
home: {
topBar: {
title: "顶部标题",
},
bottomBar: {
notes: "XXX备案,归XXX所有",
},
},
login: {
username: "用户名",
},
});
// 测试
i18n('home.bottomBar.notes')
i18n('home.topBar.title')
i18n('login.username')
// i18n('home.login.abc') // error,不存在的属性
// i18n('home.topBar') // error,没有到最后一个属性
12.定义组件的监听事件类型 ComponentEmitsType
Day2.实现内置类型
1.计算元组类型的长度 LengthOfTuple
// 实现
type LengthOfTuple<T extends any[]> = T["length"]
// 使用
type A = LengthOfTuple<['B', 'F', 'E']> // 3
type B = LengthOfTuple<[]> // 0
// 测试
let n1: A = 3
let n2: B = 0
2.元组类型中的第一个元素 FirstItem
// 实现
type FirstItem<T extends any[]> = T extends [infer L, ...infer R] ? L : never
// 使用
type A = FirstItem<[string, number, boolean]> // string
type B = FirstItem<['B', 'F', 'E']> // 'B'
// 测试
let n1: A = 'ccc'
let n2: B = 'B'
3.元组类型中的最后一个元素 LastItem
// 实现
type LastItem<T extends any[]> = T extends [...infer L, infer R] ? R : never
// 使用
type A = LastItem<[string, number, boolean]> // boolean
type B = LastItem<['B', 'F', 'E']> // 'E'
type C = LastItem<[]> // never
// 测试
let s1: A = 'ccc'
let s2: B = 'E'
function test(): C {
throw new Error('ccc')
}
4.移除元组类型中的第一个类型 Shift
// 实现
type Shift<T extends any[]> = T extends [infer L, ...infer R] ? R : T
// 使用
type A = Shift<[1, 2, 3]> // [2,3]
type B = Shift<[1]> // []
type C = Shift<[]> // []
// 测试
let a1: A = [2,3]
let a2: B = []
let a3: C = []
5.在元组类型T中添加新的类型I Push
// 实现
type Push<T extends any[], V> = [...T, V]
// 使用
type A = Push<[1,2,3], 4> // [1,2,3,4]
type B = Push<[1], 2> // [1, 2]
// 测试
let a1: A = [1,2,3,4]
let a2: B = [1, 2]
6.反转元组 ReverseTuple
// 实现
type ReverseTuple<
T extends any[],
A extends any[] = []
> = T extends [infer L, ...infer R]
? ReverseTuple<R, [L, ...A]>
: A
// 使用
type A = ReverseTuple<[string, number, boolean]> // [boolean, number, string]
type B = ReverseTuple<[1, 2, 3]> // [3,2,1]
type C = ReverseTuple<[]> // []
// 测试
let a1: A = [true, 1, 'a']
let a2: B = [3,2,1]
let a3: C = []
7.拍平元组 Flat
// 实现
type Flat<
T,
A extends any[] = []
> = T extends [infer L, ...infer R]
? [...(L extends any[] ? Flat<L> : [L]), ...Flat<R>, ...A]
: T
// 使用
type A = Flat<[1, 2, 3]> // [1,2,3]
type B = Flat<[1, [2, 3], [4, [5, [6]]]]> // [1,2,3,4,5,6]
type C = Flat<[]> // []
type D = Flat<[1]> // [1]
// 测试
let a1: A = [1,2,3]
let a2: B = [1,2,3,4,5,6]
let a3: C = []
let a4: D = [1]
8.复制类型T为C个元素的元组类型 Repeat
// 实现
type Repeat<
T extends any,
K extends number,
A extends any[] = []
> = A['length'] extends K
? A
: Repeat<T, K, [T, ...A]>
// 使用
type A = Repeat<number, 3> // [number, number, number]
type B = Repeat<string, 2> // [string, string]
type C = Repeat<1, 1> // [1]
type D = Repeat<0, 0> // []
// 测试
let a1: A = [1, 2, 3]
let a2: B = ['a', 'a']
let a3: C = [1]
let a4: D = []
9.保留元组类型T中的A类型 Filter
// 实现
type Filter<
T extends any[],
K,
A extends K[] = []
> = T extends [infer L, ...infer R]
? Filter<R, K, [L] extends [K] ? [...A, L] : [...A]>
: A
// 使用
type A = Filter<[1, 'BFE', 2, true, 'dev'], number> // [1, 2]
type B = Filter<[1, 'BFE', 2, true, 'dev'], string> // ['BFE', 'dev']
type C = Filter<[1, 'BFE', 2, any, 'dev'], string> // ['BFE', any, 'dev']
// 测试
let a1: A = [1, 2]
let a2: B = ['BFE', 'dev']
let a3: C = ['BFE', true, 'dev']
10.找出E类型在元组类型T中的下标 FindIndex<T,E>
// 实现
type Equal<T, K> = [T] extends [K]
? [K] extends [T]
? keyof T extends keyof K
? keyof K extends keyof T
? true
: false
: false
: false
: false;
type FindIndex<T extends any[], K> = T extends [...infer L, infer R]
? Equal<R, K> extends true
? L['length']
: FindIndex<L, K>
: never
// 使用
type Test = [any, never, 1, '2', true]
type A = FindIndex<Test, 1> // 2
type B = FindIndex<Test, 3> // never
// 测试
let a1: A = 2
function a2(): B {
throw new Error('ccc')
}
11.元组类型转换为枚举类型 TupleToEnum
// 实现
// 判断类型是否相等的时候都加[]
type Equal<T, K> = [T] extends [K]
? [K] extends [T]
? keyof T extends keyof K
? keyof K extends keyof T
? true
: false
: false
: false
: false;
type FindIndex<T extends any[], K> = T extends [...infer L, infer R]
? Equal<R, K> extends true
? L['length']
: FindIndex<L, K>
: never
type TupleToEnum<T extends any[], K extends boolean = false> = {
[key in T[number]]: K extends true ? FindIndex<T, key> : key
}
// 使用
// 默认情况下,枚举对象中的值就是元素中某个类型的字面量类型
type A = TupleToEnum<["MacOS", "Windows", "Linux"]>
// -> { readonly MacOS: "MacOS", readonly Windows: "Windows", readonly Linux: "Linux" }
// 如果传递了第二个参数为true,则枚举对象中值的类型就是元素类型中某个元素在元组中的index索引,也就是数字字面量类型
type B = TupleToEnum<["MacOS", "Windows", "Linux"], true>
// -> { readonly MacOS: 0, readonly Windows: 1, readonly Linux: 2 }
// 测试
let obj1: A = {
MacOS: "MacOS",
Windows: "Windows",
Linux: "Linux"
}
let obj2: B = {
MacOS: 0,
Windows: 1,
Linux: 2
}
12.截取元组中的部分元素 Slice
// 实现
type Slice<
A extends any[],
S extends number,
E extends number = A['length'],
Pre extends any[] = [],
SA extends any[] = [],
EA extends any[] = []
> = A extends [infer L, ...infer R]
? SA['length'] extends S
? EA['length'] extends E
? [...Pre, L]
: Slice<R, S, E, [...Pre, L], SA, [...EA, null]>
: Slice<R, S, E, Pre, [...SA, null], [...EA, null]>
: Pre
// 使用
type A1 = Slice<[any, never, 1, '2', true, boolean], 0, 2> // [any,never,1] 从第0个位置开始,保留到第2个位置的元素类型
type A2 = Slice<[any, never, 1, '2', true, boolean], 1, 3> // [never,1,'2'] 从第1个位置开始,保留到第3个位置的元素类型
type A3 = Slice<[any, never, 1, '2', true, boolean], 1, 2> // [never,1] 从第1个位置开始,保留到第2个位置的元素类型
type A4 = Slice<[any, never, 1, '2', true, boolean], 2> // [1,'2',true,boolean] 从第2个位置开始,保留后面所有元素类型
type A5 = Slice<[any], 2> // [] 从第2个位置开始,保留后面所有元素类型
type A6 = Slice<[], 0> // [] 从第0个位置开始,保留后面所有元素类型
// 测试
13.删除并且替换部分元素 Splice
// 实现
type Splice<
A extends any[],
S extends number,
L extends number,
V extends any[] = [],
Pre extends any[] = [],
SA extends any[] = [],
LA extends any[] = []
> = A extends [infer First, ...infer Rest]
? SA['length'] extends S
? LA['length'] extends L
? [...Pre, ...V, ...A]
: Splice<Rest, S, L, V, Pre, SA, [...LA, null]>
: Splice<Rest, S, L, V, [...Pre, First], [...SA, null], LA>
: Pre
// 使用
type A1 = Splice<[string, number, boolean, null, undefined, never], 0, 2> // [boolean,null,undefined,never] 从第0开始删除,删除2个元素
type A2 = Splice<[string, number, boolean, null, undefined, never], 1, 3> // [string,undefined,never] 从第1开始删除,删除3个元素
type A3 = Splice<[string, number, boolean, null, undefined, never], 1, 2, [1, 2, 3]> // [string,1,2,3,null,undefined,never] 从第1开始删除,删除2个元素,替换为另外三个元素1,2,3
// 测试
Day3.实现内置类型 (联合类型以及对象类型)
1.获取对象类型中的可选属性的联合类型 OptionalKeys
// 实现
type ExcludeUndefined<T> = { [key in keyof T]: Exclude<T, undefined> }
type OptionalKeys<T, K = keyof T> = K extends keyof T
? undefined extends ExcludeUndefined<T>[K]
? K
: never
: never
// 使用
type a1 = OptionalKeys<{ foo: number | undefined, bar?: string, flag: boolean }> // bar
type a2 = OptionalKeys<{ foo: number, bar?: string }> // bar
type a3 = OptionalKeys<{ foo: number, flag: boolean }> // never
type a4 = OptionalKeys<{ foo?: number, flag?: boolean }> // foo|flag
type a5 = OptionalKeys<{}>
// 测试
2.获取对象类型中的可选属性的联合类型 PickOptional
// 实现
type ExcludeUndefined<T> = { [key in keyof T]: Exclude<T, undefined> }
type OptionalKeys<T, K = keyof T> = K extends keyof T
? undefined extends ExcludeUndefined<T>[K]
? K
: never
: never
type PickOptional<T> = Pick<T, OptionalKeys<T>>
// 使用
type a1 = PickOptional<{ foo: number | undefined, bar?: string, flag: boolean }> // {bar?:string|undefined}
type a2 = PickOptional<{ foo: number, bar?: string }> // {bar?:string}
type a3 = PickOptional<{ foo: number, flag: boolean }> // {}
type a4 = PickOptional<{ foo?: number, flag?: boolean }> // {foo?:number,flag?:boolean}
type a5 = PickOptional<{}> // {}
// 测试
3.获取对象类型中的必须属性的联合类型 RequiredKeys
// 实现
type ExcludeUndefined<T> = { [key in keyof T]: Exclude<T, undefined> }
type RequiredKeys<T, K = keyof T> = K extends keyof T
? undefined extends ExcludeUndefined<T>[K]
? never
: K
: never
// 使用
type a1 = RequiredKeys<{ foo: number | undefined, bar?: string, flag: boolean }> // foo|flag
type a2 = RequiredKeys<{ foo: number, bar?: string }> // foo
type a3 = RequiredKeys<{ foo: number, flag: boolean }> // foo|flag
type a4 = RequiredKeys<{ foo?: number, flag?: boolean }> // never
type a5 = RequiredKeys<{}> // never
// 测试
4.保留一个对象中的必须属性 PickRequired
// 实现
type ExcludeUndefined<T> = { [key in keyof T]: Exclude<T, undefined> }
type RequiredKeys<T, K = keyof T> = K extends keyof T
? undefined extends ExcludeUndefined<T>[K]
? never
: K
: never
type PickRequired<T> = Pick<T, RequiredKeys<T>>
// 使用
type a1 = PickRequired<{ foo: number | undefined, bar?: string, flag: boolean }> // {foo:number|undefined,flag:boolean}
type a2 = PickRequired<{ foo: number, bar?: string }> // {foo:number}
type a3 = PickRequired<{ foo: number, flag: boolean }> // {foo:number,flag:boolean}
type a4 = PickRequired<{ foo?: number, flag?: boolean }> // {}
type a5 = PickRequired<{}> // {}
// 测试
5.合并两个对象类型T以及K,如果属性重复,则以K中属性类型为准; Merge
// 实现
// 对象属性重叠和不重叠这些优先考虑内置函数
type Merge<T, E> = { [K in Exclude<keyof T, keyof E>]: T[K] } & E
// 使用
type obj1 = { el: string, age: number }
type obj2 = { el: HTMLElement, flag: boolean }
type obj3 = Merge<obj1, obj2> // {el:HtmlElement,age:number,flag:boolean}
// 测试
const a = {...{} as obj3}
console.log(a.el.scrollTop, a.age.toFixed(0), a.flag.valueOf())
// console.log(a.el.charAt(0)) // error
6.判断是否为never类型 IsNever
// 实现
type IsNever<T> = [T] extends [never] ? true : false
// 使用
type A = IsNever<never> // true
type B = IsNever<string> // false
type C = IsNever<undefined> // false
type D = IsNever<any> // false
// 测试
7.判断是否为没有属性的对象类型{} IsEmptyType
// 实现
type IsEmptyType<T> = string extends T
? keyof T extends never
? T extends {}
? true
: false
: false
: false
// 使用
type A = IsEmptyType<string> // false
type B = IsEmptyType<{ a: 3 }> // false
type C = IsEmptyType<{}> // true
type D = IsEmptyType<any> // false
type E = IsEmptyType<object> // false 对象类型(包含number、string、boolean等)
type F = IsEmptyType<Object> // false 大写Object是一个全局变量
type G = IsEmptyType<unknown> // false
// 测试
8.判断是否为any类型 IsAny
// 实现
type IsAny<T> = unknown extends T
? [T] extends [string]
? true
: false
: false
// 使用
type A = IsAny<string> // false
type B = IsAny<any> // true
type C = IsAny<unknown> // false
type D = IsAny<never> // false
// 测试
9.实现Connect类型,能够自动地转化Redux Module对象中的函数类型 Redux Connect
10.有且只有一个属性 UnionToBooleanProps
11.将联合类型转换为交叉类型 UnionToIntersection
// 实现
// 使用函数取出联合类型的值
type UnionToIntersection<T> = (T extends any ? (t: T) => any : never) extends (r: infer R) => any
? R
: never
// 使用
type A = UnionToIntersection<{a: string} | {b: string} | {c: string}>
// {a: string} & {b: string} & {c: string}
// 测试
X12.取出联合类型中的任意一个类型 UnionPop
// 实现
// ((x: 1) => void) & ((x: 2) => void) & ((x: 3) => void) 利用重载函数只取最后一个的特性
type UnionPop<U> = (
(U extends any ? (k: (x: U) => void) => void : never) extends (
k: infer I
) => void
? I
: never
) extends (a: infer A) => void
? A
: never;
// 使用
type a = 1 | 2 | 3;
type b = UnionPop<a>; // 3
// 测试
13.联合类型转换为元组类型 UnionToTuple