基础类型的应用 实现 Exclude 从当前类型中排查掉提供的类型(提供的是类型而不是属性名,和 omit 区分开) 这个提供的类型不一定约束为当前目前类型的子类型,
当确定的类型参数为联合类型时,就会被分配类型TypeScript参考,分配条件类型
1 2 3 type MyExclude<T, U> = T extends U ? never : Ttype newType = MyExclude<string | number , string >
与 Exclude 相反,提取一个类型
1 2 3 type MyExtract<T, U> = T extends U ? T : never ;type newType = MyExtract<string | number , string >
实现 pick 通过属性名 从一个接口中提取当前属性和它的类型, 该属性名一定是当前接口的属性之一
属性名可以是一个联合属性
1 2 3 4 5 6 7 8 9 10 11 12 13 type MyPick<T, K extends keyof T> = { [P in K]: T[P] }interface testData { age: number name: string test: () => void }type a = Pick<testData, 'age' | 'name' >
实现 Omit 通过属性名 从一个接口中删除当前属性和它的类型, 该属性名一定是当前接口的属性之一
首先借用 Exclude 将不必要的属性名排除掉 ,返回新的属性名集合,再通过 Pick 用该属性名集合获取最新的接口类型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 type MyOmit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>interface testData { age: number name: string test: () => void }type a = MyOmit<testData, 'age' | 'name' > 利用映射类型过滤不需要的key [TypeScript参考,通过as 进行键重新映射](https:
type MyOmit<T, U extends keyof T> = { [key in keyof T as key extends U ? never : key]: T[key] }
type MyOmit<T, U extends keyof T> = { [key in keyof T as Exclude<key, U> ]: T[key] }
1 2 3 4 5 ### 实现 ReadOnly 将属性全变为 readonly
type MyReadOnly = { readonly [K in keyof T]: T[K] }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 还是利用as进行了键值重新映射忽略不需要的类型,最后使用交叉类型合并选项 ```javascripttype MyReadOnly2<T , U extends keyof T> = { +readonly [key in keyof T as Extract <key, U >]: T [key] } & Omit <T , U > interface testData { age: number name: string test: () => void }type d = MyReadOnly2 <testData, 'ag e' | 'nam e'>
实现 Partial & Required & DeepPartial & DeepRequired
利用映射类型的操作符 + — ? 对类型进行操作,将属性全变为可选 对象类型的可选实现,使用递归去遍历每一个属性
实现可选,则使用 +?去修饰属性,+可省略
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 type MyPartial<T> = { [K in keyof T]?: T[K] }type DeepPartial<T> = T extends object ? { [K in keyof T]?: DeepPartial<T[K]> } : Tinterface Todo { title: string description: string personal: { age: number , name: string } }type a = DeepPartial<Todo>let b: a = { title: '1321' , personal: { name: '13213' } }
实现必选,则使用 -?去修饰属性,去除原有?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 type MyRequired<T> = { [K in keyof T]-?: T[K] }type DeepRequired<T> = T extends object ? { [K in keyof T]-?: DeepRequired<T[K]> } : Tinterface Props { a?: number ; b?: string ; }type obj = MyRequired<Props>const obj2: obj = { a : 5 , b : '1231' };
实现指定可选 & 指定必选
使用pick、omit单独处理指定的部分 最后使用simplify对交叉类型进行扁平化处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 type Foo = { a: number ; b?: string ; c: boolean ; }type SetOptional<T, U extends keyof T> = Simplify<Partial<Pick<T, U>> & Omit<T, U>>type Simplify<T> = { [K in keyof T]: T[K] }type SomeOptional = SetOptional<Foo, 'a' | 'b' >;type SetRequired<T, U extends keyof T> = Simplify<Required<Pick<T, U>> & Omit<T, U>>type SomeRequired = SetRequired<Foo, 'a' | 'b' >;
实现 Record
就是遍历第一个参数的每个子类型,然后将值设置为第二参数 keyof any 得到的是 string | number | symbol
必须约束对象的属性 key 的类型为 string | number | symbol 之一
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 type MyRecord<K extends keyof any , T> = { [P in K]: T }interface a { age: number , name: string }interface b { k1: number , k2: string }type d = MyRecord<keyof a,b>
元祖转对象 传入一个元组类型,将这个元组类型转换为对象类型,这个对象类型的键/值都是从元组中遍历出来
T[number]可以获取数组元素的联合类型
1 2 3 4 5 6 7 8 9 10 11 12 const MyArray = [ { name : "Alice" , age: 15 }, { name : "Bob" , age: 23 }, { name : "Eve" , age: 38 }, ]; type Person = typeof MyArray[number]; name : string; age: number; }
1 2 3 4 5 6 7 8 9 10 11 type TupleToObject<T extends readonly any []> = { [K in T[number]]: K } const tuple = ['tesla' , 'model 3' , 'model X' , 'model Y' ] as const type v = typeof tuple [number] // "tesla" | "model 3" | "model X" | "model Y" type a = TupleToObject<typeof tuple > // expected { tesla: 'tesla' , 'model 3' : 'model 3' , 'model X' : 'model X' , 'model Y' : 'model Y' }
获取第一个元素 1 2 3 4 5 6 7 type arr1 = ['a', 'b', 'c']type arr2 = [3 , 2 , 1 ]type First<T extends any []> = T [0 ]type head1 = First <arr1> type head2 = First <arr2>
获取元组长度 创建一个通用的 Length,接受一个 readonly 的数组,返回这个数组的长度
1 2 3 4 5 6 7 type tesla = ['tesl a', 'model 3 ', 'model X ', 'model Y ']type spaceX = ['FALCON 9 ', 'FALCON HEAVY ', 'DRAGO N', 'STARSHI P', 'HUMAN SPACEFLIGHT ']type Length<T extends readonly any []> = T extends { length: infer L } ? L : nevertype teslaLength = Length <tesla> type spaceXLength = Length <spaceX>
Awaited 假如我们有一个 Promise 对象,这个 Promise 对象会返回一个类型。在 TS 中,我们用 Promise 中的 T 来描述这个 Promise 返回的类型。请你实现一个类型,可以获取这个类型。 比如:Promise,请你返回 ExampleType 类型
利用 infer 解包 约束 Promise 时使用 unknown 而非 any,因为它更安全 为什么更安全? 类型检查和函数调用,unknown会更严格,需要明确的类型才能操作,而any不用
1 2 3 4 5 6 7 8 9 let x : unknown x .split('' ) // error let x : unknown typeof x === 'number' && x .toString() let x : any x .split('' ) // no error
1 2 3 4 5 6 7 8 9 10 11 type UnPackPromise<T extends Promise<unknown>> = T extends Promise <infer R > ? R :nevertype a = UnPackPromise <Promise <string>> type MyAwait<T extends Promise<unknown>> = T extends Promise <infer R > ? R extends Promise <unknown> ? MyAwait <R > : R : nevertype a = UnPackPromise <Promise <Promise <string>>>
If Implement a utils If which accepts condition C, a truthy return type T, and a falsy return type F. C is expected to be either true or false while T and F can be any type.
1 2 3 4 type If<C extends boolean ,T ,F> = C extends true ? T : F type A = If <true , 'a', 'b'> type B = If <false , 'a', 'b'>
Concat Implement the JavaScript Array.concat function in the type system. A type takes the two arguments. The output should be a new array that includes inputs in ltr order
…展开运算法也可以使用, 拓展任意长度
1 2 3 4 5 6 type Concat<T extends any [], K extends any []> = T extends [infer R ] ? K extends [infer Q ] ? [R , Q ] : never : never;type Concat<T extends unknown [],K extends unknown []> = [ ...T , ...K ]type Result = Concat <[1 ], [2 ]>
Includes Implement the JavaScript Array.includes function in the type system. A type takes the two arguments. The output should be a boolean true or false
keyof A: 取的是 A 中所有key联合
A[keyof A]: A 所有值的联合类型
1 2 3 4 5 6 7 8 9 type Includes<A extends any [], T> = T extends A [keyof A ] ? true : false type isPillarMen = Includes <['Kar s', 'Esidis i', 'Wamu u', 'Santan a'], 'Kar s'>
先将数组变为对象结构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 type TupleToObj<T extends any []> = { [K in T [number]]: K }type dd = TupleToObj <['Kar s', 'Esidis i', 'Wamu u', 'Santan a']>type dd = { Kars : "Kars" ; Esidisi : "Esidisi" ; Wamuu : "Wamuu" ; Santana : "Santana" ; }
再通过属性调用,获取当前值与属性对比
1 2 3 4 5 6 7 8 type TupleToObj<T extends any []> = { [K in T [number]]: K }type MyIncludes<T extends any [], K> = TupleToObj <T >[K ] extends K ? true : false type isPillarMen = MyIncludes <['Kar s', 'Esidis i', 'Wamu u', 'Santan a'], 'Kar s'>
1 2 3 4 type IsEqual<T , K > = K extends T ? true : false type Includes<T extends any [], K> = T extends [infer F , ...infer R ] ? IsEqual <F , K > extends true ? true : Includes <R , K > : false
判断对象属性是否存在
1 2 type Includes2<T extends {}, K > = K extends keyof T ? true : false type isPillarMen2 = Includes2 <{a: 1 , b:2 }, 'b'| 'a'>
Push & Unshift Implement the generic version of Array.push & Array.unshift
1 2 3 4 5 type Push<T extends unknown [],K> = [...T ,K ]type Unshift<T extends unknown [],K> = [K ,...T ]type Result = Push <[1 , 2 ], '3 '> type Result = Unshift <[1 , 2 ], 0 >
部分题目参考来自https://github.com/type-challenges/type-challenges/blob/master/README.zh-CN.md https://juejin.cn/post/7009046640308781063