前言
现在前端项目ts还是用的比较多的,我之前也是只有用点基本的,比较菜,所以这次刷下ts类型体操提升下自己,我只刷了简单和中等的,太多了,干不动了。
简单
实现Pick
实现 TS 内置的 Pick<T, K>,但不可以使用它
interface Todo {
title: string
description: string
completed: boolean
}
/*
A = {
title: string;
completed: boolean;
}
*/
type A = MyPick<Todo, 'title' | 'completed'>
type MyPick<T,K extends keyof T>= {
[P in K]:T[P]
}
实现 Readonly
type MyReadonly<T>= {
readonly [P in keyof T]:T[P]
}
元组转换为对象
const tuple = ['tesla', 'model 3', 'model X', 'model Y'] as const
type TupleToObject<T extends readonly (keyof any)[]> = {
[P in T[number]]:P
}
type A = TupleToObject<typeof tuple> // expected { tesla: 'tesla', 'model 3': 'model 3', 'model X': 'model X', 'model Y': 'model Y'}
数组的第一个元素
实现一个通用First<T>,它接受一个数组T并返回它的第一个元素的类型。
type First<T extends any[]> = T extends [infer F,...infer R]?F:never
type A = First<[string,number]>
获取元组的长度
元组类型是另一种Array类型,它确切地知道它包含多少元素,以及在特定位置包含哪些类型
type Length<T extends readonly any[]> = T['length']
实现Exclude
实现内置的 Exclude<T, U> 类型,但不能直接使用它本身。
从联合类型 T 中排除 U 中的类型,来构造一个新的类型。
例如:
type MyExclude<T,U > = T extends U?never : T
type Result = MyExclude<'a' | 'b' | 'c', 'a'> // 'b' | 'c'
实现 Awaited
假如我们有一个 Promise 对象,这个 Promise 对象会返回一个类型。在 TS 中,我们用 Promise 中的 T 来描述这个 Promise 返回的类型。请你实现一个类型,可以获取这个类型。
例如:Promise<ExampleType>,请你返回 ExampleType 类型。
type ExampleType = Promise<string>
type MyAwaited<T extends Promise<any>> = T extends Promise<infer L>?L:never
type Result = MyAwaited<ExampleType> // string
If
type A = If<true, 'a', 'b'> // expected to be 'a'
type B = If<false, 'a', 'b'> // expected to be 'b'
type If<T extends boolean,A,B> = T extends true ?A:B
Concat
type Concat<T extends any[], U extends any[]> = [...T, ...U]
type Result = Concat<[1], [2]> // expected to be [1, 2]
Includes
// 将元组转换一个value为true的对象
type Includes<T extends any[], U> = {
[K in T[number]]: true
}[U] extends true
? true
: false
中等
获取函数返回类型
不使用 ReturnType 实现 TypeScript 的 ReturnType<T> 范型。
type MyReturnType<T> = T extends (...argv:any[]) => infer T ? T :never
实现 Omit
type MyExclude<T, K> = T extends K ? never : T
type MyOmit<T, K> = {
[P in keyof T as P extends MyExclude<keyof T, K> ? P : never]: T[P]
}
实现 Readonly 2
实现一个通用MyReadonly2<T, K>,它带有两种类型的参数T和K。
K指定应设置为Readonly的T的属性集。如果未提供K,则应使所有属性都变为只读,就像普通的Readonly<T>一样。
type MyReadonly2<T, K=keyof T> = {
[P in keyof T as P extends K ? never : P]: T[P]
} &
{
readonly [P in keyof T as P extends K ? P : never]: T[P]
}
// upgrade
type MyReadonly2<T, K extends keyof T = keyof T> = {
readonly [P in K]: T[P]
} & T;
元组转合集
type Arr = ['1', '2', '3']
const a: TupleToUnion<Arr> // expected to be '1' | '2' | '3'
type TupleToUnion<T extends any[]> = T[number]
最后一个元素
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
type Last<T extends any[]> = T extends [...any[],infer F]?F:never
Pop
删除元组最后一个
type arr1 = ['a', 'b', 'c', 'd']
type arr2 = [3, 2, 1]
type re1 = Pop<arr1> // expected to be ['a', 'b', 'c']
type re2 = Pop<arr2> // expected to be [3, 2]
type Pop<T extends any[]> = T extends [... infer R, infer L] ? R :never
实现shift
删除元组第一个
type arr1 = ['a', 'b', 'c', 'd']
type arr2 = [3, 2, 1]
type re1 = Pop<arr1> // expected to be ['a', 'b', 'c']
type re2 = Pop<arr2> // expected to be [3, 2]
type Shift<T extends any[]> = T extends [infer R, ...infer L] ? L :never
Promise.all
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)
declare function PromiseAll<T extends readonly unknown[]>(
args: readonly [...T]
): Promise<{ [P in keyof T]: T[P] extends Promise<infer R> ? R : T[P] }>
Type Lookup
根据其属性在并集中查找类型。 期望LookUp<Dog | Cat, 'dog'>获得Dog,LookUp<Dog | Cat, 'cat'>获得Cat。
interface Cat {
type: 'cat'
breeds: 'Abyssinian' | 'Shorthair' | 'Curl' | 'Bengal'
}
interface Dog {
type: 'dog'
breeds: 'Hound' | 'Brittany' | 'Bulldog' | 'Boxer'
color: 'brown' | 'white' | 'black'
}
type MyDog = LookUp<Cat | Dog, 'dog'> // expected to be `Dog`
type LookUp<T,U> = T extends {type:U}?T:never
Trim Left
删除开始的空格 example:
type trimed = TrimLeft<' Hello World '> // expected to be 'Hello World '
type TWhiteSpace = ' ' | '\n' | '\t'
type TrimLeft<S extends string> = S extends `${TWhiteSpace}${infer R}`
? TrimLeft<R>
: S
Trim
去除两侧空格 example:
type trimed = Trim<' Hello World '> // expected to be 'Hello World'
type TWhiteSpace = ' ' | '\n' | '\t'
type Trim<S extends string> = S extends (`${TWhiteSpace}${infer R}`|`${infer R}${TWhiteSpace}`)
? Trim<R>
: S
Capitalize
实现 Capitalize 将第一个字母转换为大写
type capitalized = Capitalize<'hello world'> // expected to be 'Hello world'
type Capitalize<S extends string> = S extends `${infer L}${infer R}`?`${Uppercase<L>}${R}`:S
Replace
替换字符串中对应的值
type replaced = Replace<'types are fun!', 'fun', 'awesome'> // expected to be 'types are awesome!'
type Replace<S extends string,F extends string,T extends string> = S extends ''?S:S extends `${infer L}${F}${infer R}`?`${ L}${T}${R}`:S
函数追加参数
type Fn = (a: number, b: string) => number
type Result = AppendArgument<Fn, boolean>
// 期望是 (a: number, b: string, x: boolean) => number
type AppendArgument<F extends (...s:any[]) => any,A> = F extends (...s:infer T) => infer R?(...s:[...T,A]) => R:never
Permutation联合转换为包含联合排列的数组
实现将联合类型转换为包含联合排列的数组的排列类型
type perm = Permutation<'A' | 'B' | 'C'>; // ['A', 'B', 'C'] | ['A', 'C', 'B'] | ['B', 'A', 'C'] | ['B', 'C', 'A'] | ['C', 'A', 'B'] | ['C', 'B', 'A']
//分布式 确定 第一个元素,再把第一个元素除去,递归确定剩余元素
type Permutation<T, P = T> = [T] extends [never]
? []
: T extends any
? [T, ...Permutation<Exclude<P, T>>]
: never
获取字符串的长度
type LengthOfString<S extends string, T extends any[] = []> = S extends `${infer L}${infer R}`
? LengthOfString<R, [...T, L]>
: T['length']
Flatten数组扁平处理
type flatten = Flatten<[1, 2, [3, 4], [[[5]]]]> // [1, 2, 3, 4, 5]
type Flatten<T extends any[]> = T extends [infer L,...infer R]?
[...(L extends any[]?Flatten<L>:[L]),...Flatten<R>]:T
Append to object添加新属性
type Test = { id: '1' }
type Result = AppendToObject<Test, 'value', 4> // expected to be { id: '1', value: 4 }
type EachObject<T> = {
[P in keyof T]: T[P]
}
type AppendToObject<T extends Record<string,any>,K extends string,V> =EachObject<{
[P in keyof T as P extends K?never:P]: T[P]
}&{[U in K]:V}>
Absolute
实现 Absolute。 接收字符串、数字或 bigint 的类型。 输出应该是一个正数字符串
type Test = -100;
type Result = Absolute<Test>; // expected to be "100"
type Numbers = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
type Absolute<T extends number | string | bigint> = `${T}` extends `${infer L}${infer R}`?`${L}` extends `${Numbers}`?`${L}${Absolute<R>}`:`${Absolute<R>}`:''
String to Union
字符串转联合类型
type Test = '123';
type Result = StringToUnion<Test>; // expected to be "1" | "2" | "3"
type StringToUnion<S extends string>=S extends `${infer L}${infer R}`? L | StringToUnion<R>:never
Merge对象合并
将两个类型合并为一个新类型。相同的key的情况下,第二个覆盖第一个
type A = {
name:string;
value:number
}
type B = {
value:string
}
type IntersectionToObj<T> = {
[P in keyof T]:T[P]
}
type Merge<F,R> = IntersectionToObj<Omit<F,keyof R>>&R
type C = Merge<A,B> // {name:string;value:string}