TS类型体操
infer
type sum = (a: number, b: number) => number;
type concat = (a: any[], b: any[]) => any[];
// Return 返回函数返回值的类型
type Return<T> = T extends (...args :any[])=> infer R ? R : T
let sumResult: Return<concat>
// 返回第一个参数的类型
type FirstArg<T> = T extends (first: infer F, ...agrs: any[]) => any ? F : T
type fa = FirstArg<(name: string,age: number) => void>
防抖函数类型推断
declare function debounce<A extends any[], R>(fn: (...args: A) => R, duration?: number):(...args: A) => void
function handler(a: number,b: number){
return a + b
}
const dHandler = debounce(handler)
dHandler(3,4)
柯里化函数ts封装
type Curried<A, R> = A extends []
? () => R : A extends [infer ARG]
? (param: ARG) => R : A extends [infer ARG, ...infer REST]
? (param: ARG) => Curried<REST, R> : never
function sum(a:number, b:number,c:number) {
return a+b+c
}
declare function curry<A extends any[], R>(fn:(...args:A) => R): Curried<A, R>
const currySum = curry(sum)
currySum(1)(2)(3)
自定义watch封装
type Watcher<T> = {
on<K extends string & keyof T>(eventName: `${K}Changed`, callback: (oldValue: T[K], newValue: T[K]) => void): void
}
declare function watch<T>(obj: T): Watcher<T>
const personWather = watch({
firstName: '张三',
lastName: 'lisi',
age: 26,
sex: '男',
level:2
})
personWather.on('levelChanged',(oldValue, newValue)=> {})
实现Optional
interface Article {
title: string;
content: string;
author: string;
date: Date;
readCount: number;
}
// omit 表示去掉 pick表示拾取 Partial表示属性变为可选类型
type Optional<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>
type CreateArticleOptions = Optional<Article, 'author'|'date'|'readCount'>
function createArticle(options: CreateArticleOptions){}
泛型应用
type JSTypeMap = {
'string':string,
'number': number,
'boolean': boolean,
'object': object,
'symbol': symbol,
'bigint': bigint,
'undefined': undefined,
'null': null
}
type JSTypeNames = keyof JSTypeMap
type ArgsType<T extends JSTypeNames[]> = {
[I in keyof T]: JSTypeMap[T[I]]
}
declare function addImpl<T extends JSTypeNames[]>(...args: [
...T,
(...args: ArgsType<T>) => any
]): void;
// 不定量参数 且后面参数类型与前面保持一致
addImpl('number','boolean','number',(a,b,c)=>{})
类型断言
// as 类型断言 允许我们手动指定一个值的类型
let str:any ="hello world"
let strLength:number = (str as string).length
never 巧用
never 主要用处是 类型收缩
// 抽象通用去除任意类型
type BanType<T,E> = T extends E ? never : T
// 抽象一个BanDate类型 去除日期类型
type BanDate<T> = T extends Date ? never : T
// x可以是任何类型 但不可以是日期
function log<T>(x: BanType<T, Date>){
console.log(x)
}
log(new Date())
非空断言
let user: string | null | undefined;
console.log(user!.toUpperCase()); // 编译正确
console.log(user.toUpperCase()); // 错误
Record
// Record<K extends keyof any, T> 的作用是将 K 中所有的属性的值转化为 T 类型。
type Property = 'key1'|'key2'
type Person = Record<Property, string>;
const p: Person = { key1: "hello 啊", key2: "树哥", };
NonNullable
// 去除类型中的 `null` 和 `undefined`
type P1 = NonNullable<string | number | undefined>; // string | number
type P2 = NonNullable<string[] | null | undefined>; // string[]
InstanceType
// 返回构造函数类型T的实例类型
class C { x = 0; y = 0; }
type D = InstanceType<typeof C>; // C
Partial 和 DeepPartial
// 浅处理
type Partial<T> = { [K in keyof T]?: T[K] };
// 深处理/递归处理
type DeepPartial<T> = T extends Function
? T
: T extends object
? { [K in keyof T]?: DeepPartial<T[K]> }
: T;
pick实现
从某一个类型中选取指定类型,组成新的类型返回
type Pick<T, K extends keyof T> = { [P in K]: T[P]; }
Exclude实现
Exclude 排除,从字面量联合类型 T 中剔除所有可以赋值给 U 的属性,然后构造一个新的类型。
type T = Exclude<"a" | "b" | "c", "a">;
// "b" | "c"
type Exclude<T, U> = T extends U ? never : T;
Omit实现
Omit 与 Pick 相反,用于从类型 T 中剔除部分属性 K 来构造类型。
type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;
as const
当 typeof 用于一个数组时,结合 const 断言,会将数组中的每一项,转换为一个联合类型。
const Placements = [
'topLeft',
'topCenter',
'topRight',
'bottomLeft',
'bottomCenter',
'bottomRight'
] as const
// 关键 [number] // 等价于 type Placement = "topLeft" | "topCenter" | "topRight" | "bottomLeft" | "bottomCenter" | "bottomRight"
type Placement = (typeof Placements)[number]
模板字面量简化重复代码
type Direction = "left" | "right" | "top" | "bottom";
type CssPadding = `padding-${Direction}`;
type CssMargin = `margin-${Direction}`;