乐趣区

关于typescript:Ts常见的手写题

感激黄子毅大佬提供的技术文章以及神光的 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
退出移动版