TS高阶内置类型实现方式

295 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第4天,点击查看活动详情

前言

这篇内容主要是本人学习TS的一些笔记整理,该篇后续会不断整理和更新,与大家相互学习,共同进步!如果有写得不准确的地方欢迎提出issue,本人在前端领域还需努力,虚心求教,欢迎大家指出!

一.TS内置类型实现方式

  • T(Type) : 在定义泛型时通常用作第一个类型变量名称
  • K(Key):表示对象中的键类型
  • V(Value):表示对象中的值类型
  • E(Element):表示元素类型
  • P (Parameters) :参数
  • U : 一个新的类型变量 

Tips:如果大家对extends的含义了解的不够清楚可以看一下掘金的这篇文章juejin.cn/post/699873…

1. Pick<T, K>(实现从类型 T 中选择出属性 K,构造成一个新的类型)

type Pick<T, K extends keyof T> = { [ I in K]: T[I] }

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

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

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

2. Readonly<T>

type Readonly<T> = { readonly [K in keyof T]: T[K] }

interface Todo {  
 title: string  
 description: string 
}  
const todo: Readonly<Todo> ={   
    title: "Hey",  
    description: "foobar" 
   }

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

3. Exclude<T, U> (从联合类型T中排除U的类型成员,来构造一个新的类型)

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

type Result = MyExclude<'a' | 'b' , 'a'> // 'b' 

注释:

  • type Result = ('a' extends 'a' ? never : 'a') | ('b' extends 'a' ? never : 'b')
  • never是所有类型的子类型即结果为:type Result = never | 'b'= 'b'

4. Extract (Exclude<T, U> 取反)

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

  type A = Extract<'key1' | 'key2', 'key1'> // 'key1'

5. Omit<T, K>泛型(Pick<T, K>取反)

type Omit<T, K extends keyof T> = { [P in keyof T as P extends K ? never : P]: T[P]; };

也可根据上方Exclude写成:

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

精简版:

type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;

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

type TodoPreview = Omit<Todo, 'description' | 'title'>

const todo: TodoPreview = {
  completed: false,
}
    
// 注释: P 是 Todo类型中的键值,as来类型断言为 P 是否为'description' | 'title'  的子类,如果是则为[never]:T[P]
// 即: 取其不是该子类的键值 =>  [P] : Todo[P]

6. Awaited(Promise<T>中 T 来描述这个 Promise 返回的类型)

type Awaited<T> = T extends PromiseLike< infer U> ? U extends PromiseLike<any> ? Awaited<U>: U : never;

精简版:

type Awaited<T> = T extends PromiseLike< infer U> ? Awaited<U> : T;

type ExampleType = Promise<string>

type Result = Awaited<ExampleType> // string

 //注释:ExampleType继承PromiseLike下的表示待推断的新类型U , 
 //string ? Awaited<string> :string,满足该条件返回该类型

7.Parameters(从一个函数类型Type的参数中使用的类型构建一个元组类型)

type Parameters<Function extends (...args: any) => any> = Function extends (...args: infer P) => any ? P : never;

const foo = (arg1: string, arg2: number): void => {}
    
type FunctionParamsType = Parameters<typeof foo> // [arg1: string, arg2: number]

二.实战演练笔记

1.获取元组长度

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

    
type tesla = ['tesla', 'model 3', 'model X', 'model Y']

type teslaLength = Length<tesla> // expected 4

2.实现元组转换为对象

type TupleToObject = { [Key in keyof T]: T[Key]};

注释:

  • keyof T用于从对象类型T中获取键值 key;

  • in用于对对象键值key进行迭代;

  • Key 就是对象键值 key 本身;

  • T[Key]是指定 Key 的值;]

type TupleToObject<T extends readonly any[]>={ [V in T[number]] : V }

注释:

  • T[number] 用于从元组 T 中获取值;
  • in 用于迭代元组值;
  • Value 是元组元素,用作构建对象的key和value。
const tuple = ['tesla', 'model 3', 'model X', 'model Y'] as const
type result = TupleToObject<typeof tuple> 
// { tesla: 'tesla', 'model 3': 'model 3', 'model X': 'model X', 'model Y': 'model Y'}

3.实现接受一个数组T并返回它的第一个元素的类型。

type First<T extends any[]>=T extends [] ? never : T[0]

  type content=First<[1,2,3]> //返回元素1类型

4.实现一个 IF 类型,它接收一个条件类型 C ,一个判断为真时的返回类型 T ,以及一个判断为假时的返回类型 F。 C 只能是 true 或者 false, T 和 F 可以是任意类型。

type IF<C extends boolean,T,F>=C extends boolean ? T :F

type A = If<true, 'a', 'b'>  // expected to be 'a'
type B = If<false, 'a', 'b'> // expected to be 'b'

5. 实现 JavaScript 内置的 Array.concat 方法

type Concat<T extends any[], U extends any[]> = [...T, ...U]

type Result = Concat<[1], [2]> // expected to be [1, 2]

总结

未完待续.....