Return Type
使用 infer
来推断函数的返回值
type MyReturnType<T extends (...args:any) => any> = T extends (...args:any) => (infer R) ?
R :
any;
// 或者
type MyReturnType<T extends Function> = T extends (...args:any) => (infer R) ?
R :
any;
Omit
封装方式
type MyOmit<T, U extends string | number | symbol> = {
[K in Exclude<keyof T, U>]: T[K]
}
使用方式
interface Todo {
title: string;
description: string;
completed: boolean;
}
type TodoPreview = MyOmit<Todo, "description">;
// TodoPreview = {
// title: string;
// completed: boolean;
//}
MyReadonly2
将输入的参数设置为 readony
type MyReadonly<T, U extends string | number | symbol> = {
readonly [K in Extract<keyof T, U>]: T[K]
} & {
[K in keyof T]: T[K]
}
或者
type Diff<A, B> = A extends B ? A : never;
type MyReadonly2<T, U extends string | number | symbol> = {readonly [K in Diff<keyof T, U>]: T[K]} & {[K in keyof T]: T[K]};
使用
interface Todo {
title: string
description: string
completed: boolean
}
const todo: MyReadonly2<Todo, 'title' | 'description'> = {
title: "Hey",
description: "foobar",
completed: false,
}
// title 和 description 将会变为 readonly
Deep Readonly
递归使用
使得一个对象内部的每一个值都变为 readonly
type DeepOnly<T> = keyof T extends never ?
T :
{readonly [K in keyof T]: DeepOnly<T[K]>}
使用方式
type X = {
x: {
a: 1
b: 'hi'
}
y: 'hey'
}
type Expected = {
readonly x: {
readonly a: 1
readonly b: 'hi'
}
readonly y: 'hey'
}
const todo: DeepReadonly<X> // should be same as `Expected`
TupleToUnion
输入元组,返回联合类型
type TupleToUnion<T> = T extends Array<infer R> ? R : never;
使用方式
type Arr = ['1', '2', '3']
const a: TupleToUnion<Arr> // expected to be '1' | '2' | '3'
Chainable
封装
type Chainable<R = {}> = {
option<K extends string | number | symbol, V>(key: K, value: V): Chainable<{
[k in K | keyof R]: k extends K ? V : k extends keyof R ? R[k] : never
}>
get(): R
}
使用方式
declare const config: Chainable
const result = config
.option('foo', 123)
.option('name', 'type-challenges')
.option('bar', { value: 'Hello World' })
.get()
Last of Array
封装
type Last<T extends any[]> = T extends [...infer _, infer L] ? L : never;
使用
type arr1 = ['a', 'b', 'c']
type arr2 = [3, 2, 1]
type tail1 = Last<arr1> // expected to be 'c'
type tail2 = Last<arr2> // expected to be 1
Pop Push Shift Unshift
type Pop<T extends unknown[]> = T extends [...infer U, unknown] ? U : never
type Push<T extends unknown[], U> = [...T, U]
type Shift<T extends unknown[]> = T extends [unknown, ...infer U] ? U : never
type Unshift<T extends unknown[], U> = [U, ...T]
Promise function
封装
declare function PromiseAll<T extends any[]>(values: readonly [...T]):
Promise<{ [K in keyof T]: T[K] extends Promise<infer R> ? R : T[K] }>;
使用
const promise1 = Promise.resolve(3);
const promise2 = 42;
const promise3 = new Promise<string>((resolve, reject) => {
setTimeout(resolve, 100, 'foo');
});
// expected to be `Promise<[number, number, string]>`
const p = Promise.all([promise1, promise2, promise3] as const)
Type Lookup
从联合类型里面找出对应的类型
封装, 先将其封装为对象,然后再使用键值来取得
type Lookup<T, U extends string> = {
[K in U]: T extends {type: U} ? T : never
}[U]
使用
interface Cat {
type: 'cat'
breeds: 'Abyssinian' | 'Shorthair' | 'Curl' | 'Bengal'
}
interface Dog {
type: 'dog'
breeds: 'Hound' | 'Brittany' | 'Bulldog' | 'Boxer'
color: 'brown' | 'white' | 'black'
}
type MyDogType = LookUp<Cat | Dog, 'dog'> // expected to be `Dog`