(建议收藏)一文详解TypeScript中的内置类型

·  阅读 444

(建议收藏)一文了解TypeScript中的内置类型(内含实现)

一、前言

一直想写一篇关于TypeScript相关的文章,对于TypeScript的基本概念,我不去做过多解释,学习完基本语法之外,我想补充一点,TypeScript是图灵完备的,因此我们不仅仅可以使用TypeScript去定义一些接口,类型;我们还可以使用TypeScript解决计算、构建、循环等所有的编程问题;

因此TypeScript的实质就是对类型进行编程,在使用TypeScript进行开发时,大部分时间我们都是自定义类型,但是TypeScript也有很多内置类型,我们如果对其足够熟悉,那么将可以大大提高我们的开发效率,如果懂其原理,那对我们深入理解TypeScript将会更有帮助!

温馨提示:本文的前提是掌握TypeScript基本语法;对于语法不熟悉的小伙伴可先收藏哦!

so are you ready? let*s get start it?

二、内置类型

  1. Parameters

    • 作用:根据传入的函数类型,推断这个函数的参数类型;

    • 实现

      type Parameters<T extends (...args: any[]) => any> = T extends (
          ...args: infer P
        ) => any
          ? P
          : never;
      
        // test
      
        type Fun = (name: string, age: number) => string;
      
        const p: Parameters<Fun> = ["", 10]; // const p: [name: string, age: number]
      
      复制代码

      其实原理并不难,就是利用的infer来推测出参数的类型;

  2. ReturnType

    • 作用:根据传入的函数,推断这个函数的返回值类型
    • 实现:
    type ReturnType<T extends (...args: any[]) => any> = T extends (
      ...args: any[]
    ) => infer R
      ? R
      : never;
    
    // test
    const r: ReturnType<Fun> = ""; // const r: string
    复制代码

    这个和Parameters是一个套路;都是利用infer来进行推导,infer在进行类型构造时非常有用,它的本质就是当我们想要获取某个类型的一部分的时候,就可以用它来进行推导并获取;

  3. ConstructorParamters

    • 作用:根据传入的构造类型,推断这个构造类型的参数类型
    • 实现:
    type ConstructorParamters<T extends new (...args: any[]) => any> 
      = T extends new (...args: infer P) => any 
      ? P 
      : never;
    type Instance = {
      name: string;
      age: number;
    };
    
    interface ClassDemo {
      new (name: string, age: number): Instance;
    }
    
    //test
    const c: ConstructorParamters<ClassDemo> = ["", 10]; //const c: [name: string, age: number]
    复制代码
  4. InstanceType

    • 作用:根据传入的构造类型,推断这个构造类型实例的类型
    • 实现:
     type InstanceType<T extends new (...args: any[]) => any> = T extends new (
       ...args: any[]
     ) => infer R
       ? R
       : never;
    
     const i: InstanceType<ClassDemo> = {
       age: 10,
       name: "",
     }; //const i: Instance
    
    复制代码
  5. Partial

    • 作用:可以让传入的类型的每个属性变为可选的;
    • 实现:
     type Partial<T extends {}> = {
       [K in keyof T]?: T[K];
     };
    
     const f: Partial<{
       name: string;
       age: number;
     }> = {
       age: 10,
     }; // no error
    复制代码

    这里要提到一个类型映射的概念
    映射类型

    • 索引查询 keyof T
    • 索引遍历 K in keyof T
    • 索引访问 T[K]

    通过上面的方式我们可以去获取一个类型的每一个Key,并重新根据这个Key构造新的类型;在这个案例中其实就是加了一个可选条件而已;

  6. Required

    • 作用:和5是刚刚相反的,这个是将可选去掉
    • 实现:
    type Required<T extends {}> = {
       [K in keyof T]-?: T[K];
     };
    
     const h: Required<
       Partial<{
         name: string;
         age: number;
       }>
     > = {
       age: 10,
       name: "",
     }; // 相当于给复原了
    
    复制代码
  7. Readonly

    • 作用:可以让传过来的类型的每一个属性变为只读的
    • 实现:
    type Readonly<T extends {}> = {
       readonly [K in keyof T]: T[K];
     };
    
     const j: Readonly<Instance> = {
       age: 10,
       name: "",
     };
     
     // test
     // j.age = 19 // error
    复制代码
  8. Pick

    • 作用:接受两个参数类型,一个基础类型,另一个是一个联合类型 ,从基础类型中过滤出属性为联合类型的属性和其属性值,重新再组成一个新的类型
    • 实现:
    type Pick<T extends {}, U extends keyof T> = {
       [R in U]: T[R];
     };
    
     // test
    
     type TestP = {
       age: number;
       name: string;
       sex: boolean;
     };
    
     type Keys = "age" | "name";
    
     const l: Pick<TestP, Keys> = {
       age: 10,
       name: "",
     };
    复制代码
  9. Record

    • 作用:接受两个参数类型,第一个参数为分配的属性范围,第二个属性具体的类型
    • 实现:
    type Record<T extends keyof any, P> = {
       [K in T]: P;
     };
    
     // test
    
     const y: Record<string, number> = {
       // key可以为任意一个字符串,值为number类型
       anystring: 10,
     };
    
    复制代码
  10. Exclude

    • 作用:当想从一个联合类型中去掉一部分类型时,可以用 Exclude 进行构造
    • 实现:
    type Exclude<T, U> = T extends U ? never : T;
    
    // test
    const n: Exclude<"a" | "b" | "c" | "d" | "e", "a" | "c"> = "b"; //const n:"b" | "d" | "e"
    复制代码

    Exclude的实现有个技巧,其实也不算技巧,就是当泛型接受的是一个联合类型的时候,实际上TypeScript在检测的时候,会依此把联合类型的每一个元素传入得到结果再联合起来;得到never时等价于没有得到任何东西。因此就有了去除的效果;

  11. Extract

    • 作用:取两个联合类型的交集
    • 实现:
    type Extract<T, U> = T extends U ? T : never;
    
    // test
    const m: Extract<"a" | "b" | "c" | "d" | "e", "a" | "c"> = "c"; //const m: "a" | "c"
    
    复制代码

    原理和10一样,我就不解释啦

  12. Omit

    • 作用:接受连个类型,从其中一个类型当中去除掉可以被另一种类型分配的属性,然后组成一个新的类型
    • 实现:
    type Omit<T extends {}, U extends keyof T> = Pick<T, Exclude<keyof T, U>>;
    
    const v: Omit<TestP, "age" | "sex"> = {
      name: "sf",
    };
    
    复制代码

    这个有点绕,多看两遍就可以理解啦;相当于从T类型当中取出一些符合条件的属性,符合什么条件呢?就是不能分配给U的的属性,那可不就是去掉啦指定的某些属性么!

  13. NonNullable

    • 作用
    • 实现:
    type NonNullable<T> = T extends undefined | null ? never : T;
    
    type Res = NonNullable<null>; //type Res = never
    复制代码
  14. Awaited

    • 作用:可以用来判断一个Promise的值类型,
    • 实现:
    type Awaited<T> = T extends Promise<infer Value> 
      ? Awaited<Value>
      : T
    
    type Test = Awaited<Promise<Promise<Promise<Promise<string>>>>> // string
    复制代码
  15. 还有几个是属于比较底层的一些方法;

截屏2022-04-27 下午10.16.16.png

看不到它的源码,但是我简单讲一下他们的作用

type Uppercase 将传入的字符串类型转为大写
type Lowercase 将传入的字符串类型转为小写

type Capitalize 将传入的字符串类型首字母转为大写
type Uncapitalize 将传入的字符串类型首字母转为小写
复制代码

三、结语

本文结合了自己对于TypeScript的浅薄理解所写,实现方面可能与源码有所出入,但是每一种类型的实现都做了测试,但是功能都是一样的,主要便于自己理解,所以敬请谅解,如果有觉得不对的欢迎指正;

另外今年的小目标是希望能够升级到L3哈哈,如果觉得有帮助的,还望点赞,关注哦,我会持续输入高质量文章的;多谢多谢😁

分类:
前端
标签:
收藏成功!
已添加到「」, 点击更改