感激黄子毅大佬提供的技术文章以及神光的 TypeScript 类型体操通关秘籍
了解常见的操作符 infer/extends/as/keyof, 须要加深了解,我第一次手写的时候齐全死记硬背,到当初基本上都能手写出了,须要一个记忆和了解的过程
实现索引类型 key 和 value 调换
type Transform1<T extends Record<any, any>> = {[K in keyof T as `${T[K]}`]: K
}
type T1011 = {
name: 'Cpp';
age: 20
}
type T111 = Transform<T101>
// type T11 = {
// Cpp: "name";
// 20: "age";
// }
转换,批改索引名, 扭转属性名
interface Test {
name: string;
age: number;
getName?: () => void}
type ChangeName1<T> = {[K in keyof T as `cpp${Capitalize<K & string>}`]: T[K]
}
type T1012 = ChangeName1<Test>
// type T10 = {
// cppName: string;
// cppAge: number;
// cppGetName?: (() => void) | undefined;
// }
依据键的属性来过滤索引类型
interface Test1 {
name: string;
age: number;
getName: () => void}
type FilterByString1<T> = {[K in keyof T as T[K] extends string ? K : never]: T[K]
}
type T81 = FilterByString1<Test1>
// {name: string}
type FilterByParams1<T, P>={[K in keyof T as T[K] extends P ? K : never]: T[K]
}
type T91 = FilterByParams1<Test1, Function>
// type T91 = {// getName: () => void;
// }
// 另外一种实现形式 不过略微简单点
type FunctionPropertyName1<T> = {[K in keyof T]: T[K] extends Function ? K : never;
}[keyof T];
type T92 = FunctionPropertyName1<Test1>
type T93 = Pick<Test1, T92>
// type T93 = {// getName: () => void;
// }
获取元素首个数据类型
type arr11 = ['a', 'b', 'c']
type arr22 = [3, 2, 1]
type First1<T extends unknown[]> = T extends [infer F, ...infer P] ? F : never
type head11 = First1<arr1> // expected to be 'a'
type head22 = First1<arr2> // expected to be 3
手写 Record 类型
interface Test {
name: string;
age: number;
getName?: () => void}
type MyRecord1<K extends string | number | symbol, T extends {}> = {[P in K]: T
}
type T61 = MyRecord<'hobby', Test>
const t61: T6 = {
hobby: {
name: '111',
age: 31
}
}
手动实现 Pick
interface Todo {
title: string
description: string
completed: boolean
}
type TodoPreview = MyPick<Todo, 'title' | 'completed'>
const todo: TodoPreview = {
title: 'Clean room',
completed: false,
}
type MyPick<T, K extends keyof T> = {[P in K]: T[P]
}
实现类型 Length<T> 获取元组长度:
type tesla = ['tesla', 'model 3', 'model X', 'model Y']
type spaceX = ['FALCON 9', 'FALCON HEAVY', 'DRAGON', 'STARSHIP', 'HUMAN SPACEFLIGHT']
type teslaLength = Length<tesla> // expected 4
type spaceXLength = Length<spaceX> // expected 5
type Length<T extends unknown[]> = T['length']
type Length2<T extends unknown[]> = T extends [...infer R] ? R['length'] : never
type T21 = Length2<tesla>
// type T21 = 4
实现类型 Exclude<T, U>,返回 T 中不存在于 U 的局部
type T24 = 'a' | 'b' | 'c'
type T23 = 'a' | 'b'
type Exclude1<T, U> = T extends U ? never : T;
type T25 = Exclude1<T24, T23>
// type T25 = "c"
实现类型 Awaited,比方从 Promise<ExampleType> 拿到 ExampleType
type T26 = Promise<[Promise<{name: 'cpp'}>,2,3]>
type MyPromise<T> = T extends Promise<infer A> ? A : never;
type T27 = MyPromise<T26>
还须要思考嵌套 Promise 类型
type T28 = Promise<[1,2,3]>
type MyAwaited<T extends Promise<unknown>> =
T extends Promise<infer A>
? A extends Promise<unknown> ? MyAwaited<A> : A
: never
type T29 = MyAwaited<T28>
type P1 = Promise<[3,4]>
type T30 = MyAwaited<Promise<[P1,2,3]>>
// type T29 = [1, 2, 3]
// type T30 = [P1, 2, 3]
实现类型 If<Condition, True, False>,当 C 为 true 时返回 T,否则返回 F:
type A = If<true, 'a', 'b'> // expected to be 'a'
type B = If<false, 'a', 'b'> // expected to be 'b'
type If<B extends Boolean, A, C> = B extends true ? A : C;
用类型零碎实现 Concat<P, Q>,将两个数组类型连起来
type Result = Concat<[1], [2]> // expected to be [1, 2]
type Concat<A extends unknown[], B extends unknown[]> = [...A, ...B]
type T31 = Concat<[1,[2,3]], [4]>
type Concat2<A,B> = [...A extends any[] ? A : [A],
...B extends any[] ? B : [B]
]
// 如何实现数组的多重解构之后的组合??
用类型零碎实现 Includes<T, K> 函数:
type isPillarMen = Includes<['Kars', 'Esidisi', 'Wamuu', 'Santana'], 'Kars'> // expected to be `false`
type Includes1<T extends any, B extends string> = B extends T ? true : false;
type isT32 = Includes1<'Kars' | 'Esidisi' | 'Wamuu' | 'Santana', 'Kars'> // expected to be `false`
type Includes<T extends any[], A> = A extends T[number] ? true: false;
type T33 = Includes<['a', 'b'], 'c'>
type T34 = Includes<[boolean], false>
type T35 = Includes<[boolean], true>
起因很简略,true、false 都继承自 boolean,所以 extends 判断的界线太宽了,题目要求的是准确值匹配,故下面的答案实践上是错的。
type Equal<X, Y> = (<T>() => T extends X ? 1 : 2
) extends (<T>() => T extends Y ? 1 : 2
) ? true : false;
type T36 = Equal<boolean, false >
采纳递归 + infer + 解构的形式遍历每一个是否相等而后得出结论
type Includess<T extends any[], A> =
T extends [infer F, ...infer R]
? Equal<F, A> extends true ? true : Includess<R, A>
: false
type T37 = Includess<[boolean], true> // type T37 = false
实现 Push<T, K> 函数:
type Result1 = Push<[1, 2], '3'> // [1, 2, '3']
type Push<T extends any[], A> = [...T, A]
实现 Unshift<T, K> 函数:
type Result2 = Unshift<[1, 2], 0> // [0, 1, 2,]
type Unshift<T extends any[], A> = [A, ...T]
实现内置函数 Parameters:
type Parameters1<T extends (...args: any) => void> = T extends (...arg: infer P) => void ? P : never;
function SayName(name: string): string | number {return 'cpp' + name;}
type T38 = Parameters1<typeof SayName>
// type T38 = [name: string]
实现内置函数 ReturnTypes
function SayName(name: string): string | number {return 'cpp' + name;}
type ReturnType2<T extends (...args: any) => void> = T extends (...arg: any) => infer R ? R : never;
type T39 = ReturnType2<typeof SayName>
// type T39 = string | number