ts的类型工具

看了一遍阮一峰的ts文档,地址:https://wangdoc.com/typescript/utility#capitalizestringtype。ts提供了一些类型工具,在此记录一下,做个总结,加深印象。

字符串的类型工具4种:

Uppercase<S> 字母大写

Lowercase<S> 字母小写

Capitalize<S> 首字母大写

Uncapitalize<S> 首字母小写

其他类型有18种,但其中的3种 OmitThisParameter<Type>ThisParameterType<Type>ThisType<Type>主要是用于this的处理,应用场景少见,所以就不加强记忆了,剩下的15种,我根据处理的类型,即工具入参类型进行分类:

         1. 处理Promise,即工具入参为Promise,有1种

    1)Awaited<Promise>    

         2.处理构造函数,有2种

    1)ConstructorParameters<Class>

    2)InstanceType<Class>    

         3. 处理对象类型,有6种

    1)Omit<Object,K>

    2)Pick<Object,K>

    3)Readonly<Object>

    4)ReadonlyArray<T>

    5)Partial<Object> 

    6)Required<Object>  

         4. 处理方法,有2种
    1)Parameters<Function>

    2)ReturnType<Function>  

         5. 处理联合类型,有4种

    1)Exclude<T,U>

    2Extract<T,U>

    3NonNullable<T>

    4)Record<K,T> 

1. Awaited<P> 返回promise的数据类型

Awaited<P>用来取Promise的返回值,比如描述.then()和await方法返回值。

type DataType = {
  code: number,
  data: string,
  msg: string
}

export function getDataById(): Promise<DataType> {
  return new Promise((resolve) => {
    resolve({
      code: 0,
      data: "我是返回的数据",
      msg: "success"
    })
  })
}

/* 两种A的定义都可以,相当于 type A = DataType */
// type A = Awaited<Promise<DataType>>
type A = Awaited<ReturnType<typeof getDataById>>
const data: A = {
  code: 0,
  data: "",
  msg: ""
}

2. ConstructorParameters<Class> 提取构造方法的参数类型,并通过元组类型返回

ConstructorParameters<C>入参是一个构造方法,可以new的,它用于将new时传入的参数类型提取出来,并用一个数组合并返回。

class Demo {
  constructor(x: number, y: string) { }
}
/* 相当于 A = [x:number,y:string] */
type A = ConstructorParameters<typeof Demo>
const data1: A = [1, "字符串"]

/* 相当于 A = [x:number,y?:string] */
type B = ConstructorParameters<new (x: number, y?: string) => object>
const data2: B = [1]
const data3: B = [1,"我是可填的字符串"]

3. InstanceType<Class> 提取构造函数的返回值的类型,也就是返回实例类型

 InstanceType<Class>入参是一个构造函数,返回的是这个实例

class Demo {
  constructor(x: number, y: string) { }
}
type Z = InstanceType<typeof Demo>
// 以下两种写法意义一样
const demo1: Z = new Demo(1, "1")
const demo2: Demo = new Demo(2, "bbb")

4. Pick<Object,T> 从对象类型中,挑出T中指定的键名,返回一个新的对象类型

从对象类型Object中,挑选出联合类型T中的键名,将挑选出来的组成一个新的对象类型进行返回。注意:T必须是对象类型中已经存在的键名,不然会报错的。

type O = {
  name: string,
  address: string,
  otherInfo: {
    hobby: string,
    desc: string
  }
}
/* 相当于 P1 = {name:string,address:string} */
type P1 = Pick<O, 'name' | 'address'>
const p: P1 = {
  name: "张三",
  address: "中国"
}
/* 报错了,noExist这个键名不存在O中 */
type P2 = Pick<O, 'name' | 'noExist'> 

Pick的实现如下:

type Pick<O,T extends keyof O> = {
  [P in T]:O[p]  
}

从实现中能看到,T必须是O存在的键名,不然读取O[P]就要报错了,那我们调整一下,传的T可以是O不存在的键名,最后返回结果与Pick一样。

/* P为T与O键名的交叉集,这样就保证键名P一定存在于O */
type PickAdjust<O, T extends keyof any> = {
  [P in Extract<T, keyof O>]: O[P]
}

再调整一下,改为可以传不存在的键名,不存在的键名就给定any类型。

/* 
  允许T任何类型,然后再通过extends ? 三木运算符给值
  如果再严谨一点,改为 T extends keyof number|string|symbol
*/
type PickAdjust<O, T extends keyof any> = {
  [P in T]: P extends keyof O ? O[P] : any
}
type O = {
  name: string,
  address: string,
  otherInfo: {
    hobby: string,
    desc: string
  }
}
// P = {name:string,age:any}
 
type P = PickAdjust<O, "name" | 'age'>
const p: P = {
  name: "",
  age: ""
}
 

5. Omit<Object,T> 从对象类型中,去掉T中指定的键名,返回一个新的对象类型

Omit<Object,T>,从对象类型中,剔除T有提过的键名,返回一个新的对象,这跟Pick相反,一个是留,一个是去。

type O = {
  name: string,
  address: string,
  otherInfo: {
    hobby: string,
    desc: string
  }
}
/* 
  M相当于O去掉了name和noexist属性
  去掉的键名中传O中不存在的键名也是没关系的
*/
type M = Omit<O, 'name' | 'noExist'>
const m: M = {
  address: "中国",
  otherInfo: {
    hobby: '保护世界',
    desc: '世界和平'
  }
}

Omit<Object,T> 实现如下:

type Omit<O, T> = Pick<O, Exclude<keyof O, T>>

6. Partial<Object> 将对象的所有属性都变为可选,返回一个新的对象类型

Partial<Object>将对象所有属性都变为可选,K?:T

type O = {
  name: string,
  address: string,
  otherInfo: {
    hobby: string,
    desc: string
  }
}
/* O中所有的属性都变为可选 */
type X = Partial<O>
const x: X = {
  name: "张三"
}

!!! 注意,属性的类型如果为对象类型,那还是按照它自身的情况规定可选或必选,这玩意不能传递哈
就比如上面的otherInfo是可选的,但如果你选了它,那它的【hobby】【desc】是必选的,这不能传递到下面。

Partial<Object>实现如下:

type Partial<O> = {
  [P in keyof O]?: O[P]
}

7. Required<Object>将对象的所有属性都变为必选,返回一个新的对象类型

Required<Object>将对象所有属性都变为必选,与Partial<Object>相反,K-?:T,将这?减掉

type O = {
  name: string,
  age?: number,
  otherInfo: {
    hobby?: string,
    desc: string
  }
}
type R = Required<O>
/* 
  上面O中的age可选,变为了必选
  但otherInfo中的hobby还是可选,不会被影响,因为这个不会传递
*/
const r: R = {
  name: "李四",
  age: 18,
  otherInfo: {
    desc: "世界和平"
  }
}

Required<Object>实现如下:

type Required<O> = {
  [P in keyof O]-?: O[P]
}

8. Readonly<Object> 将对象的所有属性都变为只读,返回一个新的对象类型

Readonly<Object>将对象所有属性都变为只读,readonly  K:T ,如果是去掉只读,可以写 readonly  K:T

type O = {
  name: string,
  age?: number,
  otherInfo: {
    hobby?: string,
    desc: string
  }
}
type R = Readonly<O>
const r: R = {
  name: "李四",
  age: 18,
  otherInfo: {
    desc: "旧的描述"
  }
}
/* 报错 name属性只读,不可赋值 */
r.name = "123"
/* 正确 因为只读标志不会传递 */
r.otherInfo.desc = "新的描述"

Readonly<Object>实现如下:

type Readonly<O> = {
  readonly [P in keyof O]: O[P]
}

9. ReadonlyArray<T>用来生成一个只读数组

ReadonlyArray<T>数组只读,不可再修改数组,它的push,splice,pop等都不存在不可用

const values: ReadonlyArray<string>  = ['a', 'b', 'c'];
values[0] = 'x'; // 报错
values.push('x'); // 报错
values.pop(); // 报错
values.splice(1, 1); // 报错

ReadonlyArray<T>实现如下:

interface ReadonlyArray<T>{
  readonly length:number
  readonly [n:number]:T
}

10. Parameters<Function>提取方法的入参类型,返回一个元组类型

Parameters<Function>接收一个函数类型,将入参提取出来,并组合为元组类型进行返回。如果该函数没有入参,那就返回一个空数组。

function JoinArg(x: number, y: string): string {
  return x + y
}
/* A = [number,string] */
type A = Parameters<typeof JoinArg>
const a: A = [1, ""]

/* B = [] */
type B = Parameters<() => {}>
const b: B = []

Parameters<Function>实现如下:

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

11. ReturnType<Function>返回方法的返回值的类型

ReturnType<Function>接受一个函数类型,返回函数返回值的类型。

type R1 = ReturnType<() => void> // void
type R2 = ReturnType<() => {}> // {}
type R3 = ReturnType<() => { x: number, y: string }> // {x: number, y: string }
type R4 = ReturnType<() => Array<string>> // Array<String>

ReturnType<Function>实现如下:

type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : never

12. Exclude<U,E>从U中剔除E,组合新的类型返回

Exclude<U,E>用来从联合类型U中,剔除某些类型E,组合成一个新的类型返回。可以理解为 U-E的值,如果E中有U不包含的,直接忽略。

type A = number | string | Array<string>
type B = number | boolean
type T1 = Exclude<A, B> // number | Array<string>
type T2 = Exclude<200 | 400, 200 | 201>; // 400
type T3 = Exclude<number, boolean>; // number
type T4 = Exclude<string | string[], any[]>; // string
type T5 = Exclude<(() => void) | null, Function>; // null

Exclude<U,T>实现如下:

type Exclude<U,T> = U extends T ? never:U

Exclude<number|string,number|boolean>结果是string,number|string是一个联合类型,进行条件运算时,相当于AB分别进行运算符,返回结果组成一个联合类型。

上面的相当于number extends number|boolean,结果true,得到never;string extends number|boolean,结果false,得到string,集合的结果就是never|string,由于never类型是任何其他类型的子类型,它跟其他类型组成联合类型时,可以直接将never类型从联合类型中消掉,所以结果就是string。

13. Extract<U,E>从U中提取出与E的交集,组合新的类型返回

Extract<U,E>从联合类型U中取出E提到的类型,组合成一个新的类型返回。如果E提到的类型在U中不存在,直接忽略。它跟Exclude相反,获取的是U与E的交叉类型

type T1 = Extract<'a'|'b'|'c', 'a'>; // 'a'
type T2 = Extract<'a'|'b'|'c', 'a'|'b'>; // 'a'|'b'
type T3 = Extract<'a'|'b'|'c', 'a'|'d'>; // 'a'
type T4 = Extract<string | string[], any[]>; // string[]
type T5 = Extract<(() => void) | null, Function>; // () => void
type T6 = Extract<200 | 400, 200 | 201>; // 200

Extract<U,E>实现如下:

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

14. NonNullable<U>从U中剔除null,undefined类型,组合新的类型返回

NonNullable<U>返回非空类型,从联合类型中剔除null,undefined类型。

// string|number
type T1 = NonNullable<string|number|undefined>;

// string[]
type T2 = NonNullable<string[]|null|undefined>;

type T3 = NonNullable<boolean>; // boolean
type T4 = NonNullable<number|null>; // number
type T5 = NonNullable<string|undefined>; // string
type T6 = NonNullable<null|undefined>; // never

NonNullable<T>实现如下:

type NonNullable<T> = T & {}

由于 TypeScript 的非空值都属于Object的子类型,所以会返回自身;而nullundefined不属于Object,会返回never类型。

15. Record<K,T>K作为键名,T作为键值,组合为一个新的对象类型返回

Record<K,T>将联合类型K作为对象类型的键名,T作为键值,组成一个新的对象类型进行返回。

type T = Record<'a', number>;// {a:number}

type T = Record<'a'|'b', number>;// { a: number, b: number }

type T = Record<'a', number|string>;// { a: number|string }

Record<K,T>实现如下:

type Record<K extends string|number|symbol,T>={
  [P in K]:T  
}

16.1. Uppercase<StringType> 字母大写

16.2. Lowercase<StringType> 字母小写

16.3. Capitalize<StringType> 首字母大写

16.4. Uncapitalize<StringType> 首字母小写

type A = 'hello';
type B = Uppercase<A>;// "HELLO"



type A = 'HELLO';
type B = Lowercase<A>;// "hello"



type A = 'hello';
type B = Capitalize<A>;// "Hello"



type A = 'HELLO';
type B = Uncapitalize<A>;// "hELLO"

 

posted @ 2024-04-29 14:17  蛙仔  阅读(221)  评论(0编辑  收藏  举报