Typescript 练习

Typescript 练习

简单

实现 pick

实现 TS 内置的 Pick<T, K>,但不可以使用它。从类型 T 中选择出属性 K,构造成一个新的类型。

interface Todo {
    title: string
    description: string
    completed: boolean
}

type MyPick<T, K extends keyof T> = {
    [P in K]: T[P]
}

type TodoPreview = MyPick<Todo, 'title' | 'completed'>

const todo: TodoPreview = {
    title: 'Clean room',
    completed: false,
}

实现 Readonly

不要使用内置的Readonly<T>,自己实现一个。该 Readonly 会接收一个 泛型参数,并返回一个完全一样的类型,只是所有属性都会被 readonly 所修饰。 也就是不可以再对该对象的属性赋值。

interface Todo {
  title: string
  description: string
}

type MyReadonly<T> = {
    readonly [R in keyof T]: T[R]
}

const todo: MyReadonly<Todo> = {
  title: "Hey",
  description: "foobar"
}

todo.title = "Hello" // Error: cannot reassign a readonly property
todo.description = "barFoo" // Error: cannot reassign a readonly property

元组转换为对象

传入一个元组类型,将这个元组类型转换为对象类型,这个对象类型的键/值都是从元组中遍历出来。

const tuple = ['tesla', 'model 3', 'model X'] as const;

type TupleToObject<T extends Record<any, any>> = {
    [P in T[number]] : P
}

type result = TupleToObject<typeof tuple> // expected { tesla: 'tesla', 'model 3': 'model 3', 'model X': 'model X'}

第一个元素

实现一个通用First<T>,它接受一个数组T并返回它的第一个元素的类型。

type arr1 = ['a', 'b', 'c']
type arr2 = [3, 2, 1]

type First<T extends any[]> =  T extends [infer First, ...infer Rest] ? First : never

type head1 = First<arr1> // expected to be 'a'
type head2 = First<arr2> // expected to be 3

获取元组长度

创建一个通用的Length,接受一个readonly的数组,返回这个数组的长度。

type tesla = ['tesla', 'model 3', 'model X', 'model Y']
type spaceX = ['FALCON 9', 'FALCON HEAVY', 'DRAGON', 'STARSHIP', 'HUMAN SPACEFLIGHT']

type Length<T extends readonly any[]> = T['length']

type teslaLength = Length<tesla> // expected 4
type spaceXLength = Length<spaceX> // expected 5

Exclude

实现内置的Exclude <T, U>类型,但不能直接使用它本身。从联合类型T中排除U的类型成员,来构造一个新的类型。

type MyExclude<T, U> = T extends U ? never : T;

Awaited

假如我们有一个 Promise 对象,这个 Promise 对象会返回一个类型。在 TS 中, 我们用 Promise 中的 T 来描述这个 Promise 返回的类型。请你实现一个类型,可以获取这个类型。 比如:Promise<ExampleType>,请你返回 ExampleType 类型。

type MyAwaited<T> = T extends Promise<infer R> ? (R extends Promise<any> ? MyAwaited<R> : R) : T; 

Awaited

假如我们有一个 Promise 对象,这个 Promise 对象会返回一个类型。在 TS 中,我们用 Promise 中的 T 来描述这个 Promise 返回的类型。请你实现一个类型,可以获取这个类型。

比如:Promise<ExampleType>,请你返回 ExampleType 类型。

type MyAwaited<T> = T extends Promise<infer V> ? V extends Promise<unknown> ? MyAwaited<V> : V : never;

If

实现一个 If 类型,它接收一个条件类型 C ,一个判断为真时的返回类型 T ,以及一个判断为假时的返回类型 FC 只能是 true 或者 falseTF 可以是任意类型。

举例:

type A = If<true, 'a', 'b'>  // expected to be 'a'
type B = If<false, 'a', 'b'> // expected to be 'b'
type If<C extends boolean, T = any, F = any> = C extends true ? T : F;

Concat

在类型系统里实现 JavaScript 内置的 Array.concat 方法,这个类型接受两个参数,返回的新数组类型应该按照输入参数从左到右的顺序合并为一个新的数组。

举例,

type Result = Concat<[1], [2]> // expected to be [1, 2]
type Concat<T extends unknown[], U extends unknown[]> = [...T, ...U];

Includes

在类型系统里实现 JavaScript 的 Array.includes 方法,这个类型接受两个参数,返回的类型要么是 true 要么是 false

举例来说,

type isPillarMen = Includes<['Kars', 'Esidisi', 'Wamuu', 'Santana'], 'Dio'> // expected to be `false`
type IsEqual<X, Y> = (<T>() => T extends X ? true : false) extends (<T>() => T extends Y ? true : false) ? true : false

type Includes<U extends readonly any[], T> = U extends [infer F, ...infer R] ? IsEqual<F, T> extends true ? true :Includes<R, T> : false;