TS学习心得

102 阅读1分钟

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}`;