Blog
首页
文档
收藏
关于
  • 在线转换时间戳 (opens new window)
  • 在线压缩图片 (opens new window)
  • Float-Double转二进制 (opens new window)
  • 文件转Hex字符串 (opens new window)

HiuZing

🍑
首页
文档
收藏
关于
  • 在线转换时间戳 (opens new window)
  • 在线压缩图片 (opens new window)
  • Float-Double转二进制 (opens new window)
  • 文件转Hex字符串 (opens new window)
  • 前端面试题

  • JavaScript

  • Vue2

  • port

  • CSS

  • Node.js

  • JavaScript优化

  • uniapp

  • Mini Program

  • TypeScript

    • 基础

      • TypeScript介绍
      • TypeScript基础类型
      • TypeScript对象类型
      • TyprScript类型推论
      • TypeScript高级类型
      • TypeScript接口
      • TypeScript类型别名与接口的区别
      • TypeScript泛型
        • TypeScript项目配置
      • 实例

    • 面向对象编程

    • UI组件

    • Plugin

    • Vue3

    • 性能优化

    • Axios

    • 状态管理

    • React

    • Mock

    • Icon

    • Template

    • 构建工具

    • 项目规范配置

    • Taro

    • SVG

    • React Native

    • 前端
    • TypeScript
    • 基础
    HiuZing
    2022-09-27
    目录

    TypeScript泛型

    软件工程中,我们不仅要创建一致的定义良好的API,同时也要考虑可重用性

    不用泛型的话,这个函数可能是下面这样:

    function getValue(arg: number): number {
        return arg;
    }
    
    1
    2
    3

    现在需求有变,需要返回一个 number 类型的值,你会说,联合类型就完事了:

    function getValue(arg:string | number):string | number  {
      return arg;
    }
    
    1
    2
    3

    或者,我们使用any类型来定义函数:

    function getValue(arg: any): any {
        return arg;
    }
    
    1
    2
    3

    尽管 any 大法好,很多时候 any 也确实能够解决不少问题,但是这样也不符合我们的需求了,传入和返回都是 any 类型,传入和返回并没有统一

    # 基本使用(一个参数)

    因此,我们需要一种方法使返回值的类型与传入参数的类型是相同的

    我们使用了类型变量,它是一种特殊的变量,只用于表示类型而不是值

    泛型的语法是尖括号 <> 里面写类型参数,一般用 T 来表示第一个类型变量名称:

    function getValue<T>(arg:T):T  {
      return arg;
    }
    
    1
    2
    3

    泛型就像一个占位符一个变量,在使用的时候我们可以将定义好的类型像参数一样传入,原封不动的输出

    # 两种方式使用:

    • 定义要使用的类型

      getValue<string>('宝贝'); // 定义 T 为 string 类型
      
      1
    • 利用 typescript 的类型推断

      getValue('宝贝') // 自动推导类型为 string
      
      1

    # 多个参数

    其实并不是只能定义一个类型变量,我们可以引入希望定义的任何数量的类型变量。比如我们引入一个新的类型变量 U

    function getValue<T, U>(arg:[T,U]):[T,U] {
      return arg;
    }
    
    // 使用
    const str = getValue(['树哥', 18]);
    
    1
    2
    3
    4
    5
    6

    # 泛型约束

    在函数内部使用泛型变量的时候,由于事先不知道它是哪种类型,所以不能随意的操作它的属性或方法:

    function getLength<T>(arg: T): T {
        console.log(arg.length);  // Error: T doesn't have .length
        return arg;
    }
    
    1
    2
    3
    4

    因为泛型 T 不一定包含属性 length,那么我想 getLength 这个函数只允许传入包含 length 属性的变量,该怎么做呢

    interface Lengthwise {
      length: number;
    }
    
    function getLength<T extends Lengthwise>(arg:T):T  {
      console.log(arg.length); 
      return arg;
    }
    
    1
    2
    3
    4
    5
    6
    7
    8

    使用:

    const str = getLength('宝贝')
    const arr = getLength([1,2,3])
    const obj = getLength({ length: 5 })
    
    1
    2
    3

    # 泛型接口

    在定义接口的时候指定泛型

    interface KeyValue<T,U> {
      key: T;
      value: U;
    }
    
    const person1:KeyValue<string,number> = {
      key: '树哥',
      value: 18
    }
    const person2:KeyValue<number,string> = {
      key: 20,
      value: '张麻子'
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13

    # 泛型类

    class Test<T> {
      value: T;
      add: (x: T, y: T) => T;
    }
    
    let myTest = new Test<number>();
    myTest.value = 0;
    myTest.add = function (x, y) {
      return x + y;
    };
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10

    # 泛型类型别名

    type Cart<T> = { list: T[] } | T[];
    let c1: Cart<string> = { list: ["1"] };
    let c2: Cart<number> = [1];
    
    1
    2
    3

    # 泛型参数的默认类型

    我们可以为泛型中的类型参数指定默认类型。当使用泛型时没有在代码中直接指定类型参数,从实际值参数中也无法推测出时,这个默认类型就会起作用。有点 js 里函数默认参数的意思。

    function createArray<T = string>(length: number, value: T): Array<T> {
      let result: T[] = [];
      for (let i = 0; i < length; i++) {
        result[i] = value;
      }
      return result;
    }
    
    1
    2
    3
    4
    5
    6
    7

    # 泛型工具类型

    1. typeof

      除了做类型保护,还可以从实现推出类型

      //先定义变量,再定义类型
      let p1 = {
        name: "树哥",
        age: 18,
        gender: "male",
      };
      type People = typeof p1;
      function getName(p: People): string {
        return p.name;
      }
      getName(p1);
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
    2. keyof

      用来获取一个对象接口中的所有 key 值

      interface Person {
        name: string;
        age: number;
        gender: "male" | "female";
      }
      
      type PersonKey = keyof Person; //type PersonKey = 'name'|'age'|'gender';
      
      function getValueByKey(p: Person, key: PersonKey) {
        return p[key];
      }
      let val = getValueByKey({ name: "树哥", age: 18, gender: "male" }, "name");
      console.log(val); // 树哥
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
    3. in

      用来遍历枚举类型

      type Keys = "a" | "b" | "c"
      
      type Obj =  {
        [p in Keys]: any
      } // -> { a: any, b: any, c: any }
      
      1
      2
      3
      4
      5
    4. infer

      在条件类型语句中,可以用 infer 声明一个类型变量并且对它进行使用

      infer R 就是声明一个变量来承载传入函数签名的返回值类型,简单说就是用它取到函数返回值的类型方便之后使用

      type ReturnType<T> = T extends (
        ...args: any[]
      ) => infer R ? R : any;
      
      1
      2
      3
    5. extends

      有时候我们定义的泛型不想过于灵活或者说想继承某些类等,可以通过 extends 关键字添加泛型约束

      interface Lengthwise {
        length: number;
      }
      
      function loggingIdentity<T extends Lengthwise>(arg: T): T {
        console.log(arg.length);
        return arg;
      }
      
      1
      2
      3
      4
      5
      6
      7
      8

      现在这个泛型函数被定义了约束,因此它不再是适用于任意类型:

      loggingIdentity(3);  // Error, number doesn't have a .length property
      loggingIdentity({length: 10, name: '张麻子'}); // 编译正确
      
      1
      2
    6. 索引访问操作符

      使用 [] 操作符可以进行索引访问:

      interface Person {
        name: string;
        age: number;
      }
      
      type x = Person["name"]; // x is string
      
      1
      2
      3
      4
      5
      6

    # 内置工具类型

    1. Required

      将类型的属性变成必选

      interface Person {
          name?: string,
          age?: number,
          hobby?: string[]
      }
      
      const user: Required<Person> = {
          name: "宝贝",
          age: 18,
          hobby: ["code"]
      }
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
    2. Partial

      与 Required 相反,将所有属性转换为可选属性

      interface Person {
          name: string,
          age: number,
      }
      
      const user:Person = {
        name:'宝贝'
      }
      // error  Property 'age' is missing in type '{ name: string; }' but required in type 'Person'.
      // 从上面知道,如果必传而我们少传了的话,就会报错
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10

      使用 Partial 将其变为可选

      type User = Partial<Person>
      
      const user: User={
        name:'树哥'
      } // 编译正确
      
      1
      2
      3
      4
      5
    3. Exclude

      Exclude<T, U> 的作用是将某个类型中属于另一个的类型移除掉,剩余的属性构成新的类型

      type T0 = Exclude<"a" | "b" | "c", "a">; // "b" | "c"
      type T1 = Exclude<"a" | "b" | "c", "a" | "b">; // "c"
      type T2 = Exclude<string | number | (() => void), Function>; // string | number
      
      1
      2
      3
    4. Extract

      和 Exclude 相反,Extract<T,U> 从 T 中提取出 U

      type T0 = Extract<"a" | "b" | "c", "a" | "f">; // "a"
      type T1 = Extract<string | number | (() => void), Function>; // () =>void
      
      1
      2
    5. Readonly

      把数组或对象的所有属性值转换为只读的,这就意味着这些属性不能被重新赋值

      interface Person {
        name: string;
        age: number;
        gender?: "male" | "female";
      }
      
      let p: Readonly<Person> = {
        name: "hello",
        age: 10,
        gender: "male",
      };
      p.age = 11; // error  Cannot assign to 'age' because it is a read-only property.
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
    6. Record

      Record<K extends keyof any, T> 的作用是将 K 中所有的属性的值转化为 T 类型

      type Property = 'key1'|'key2'
      type Person = Record<Property, string>;
      
      const p: Person = {
        key1: "hello",
        key2: "宝贝",
      };
      
      1
      2
      3
      4
      5
      6
      7
    7. Pick

      从某个类型中挑出一些属性出来

      type Person = {
        name: string;
        age:number;
        gender:string
      }
      
      type P1 = Pick<Person, "name" | "age">; // { name: string; age: number; }
      
      const user:P1={
        name:'宝贝',
        age:18
      }
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
    8. Omit

      与Pick相反,Omit<T,K> 从T中取出除去K的其他所有属性

      interface Person {
        name: string,
        age: number,
        gender: string
      }
      type P1 = Omit<Person, "age" | "gender">
      const user:P1  = {
        name: '宝贝'
      }
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
    9. NonNullable

      去除类型中的 null 和 undefined

      type P1 = NonNullable<string | number | undefined>; // string | number
      type P2 = NonNullable<string[] | null | undefined>; // string[]
      
      1
      2
    10. ReturnType

      用来得到一个函数的返回值类型

      type Func = (value: string) => string;
      const test: ReturnType<Func> = "1";
      
      1
      2
    11. Parameters

      用于获得函数的参数类型所组成的元组类型

      type P1 = Parameters<(a: number, b: string) => void>; // [number, string]
      
      1
    12. InstanceType

      返回构造函数类型T的实例类型

      class C {
        x = 0;
        y = 0;
      }
      
      type D = InstanceType<typeof C>;  // C
      
      1
      2
      3
      4
      5
      6

    具体来源 (opens new window)

    #TS
    上次更新: 2024/08/14, 04:14:33
    TypeScript类型别名与接口的区别
    TypeScript项目配置

    ← TypeScript类型别名与接口的区别 TypeScript项目配置→

    最近更新
    01
    React Native 使用SVG
    08-13
    02
    Docker基础命令
    08-04
    03
    算数逻辑单元
    07-30
    更多文章>
    Theme by Vdoing | Copyright © 2021-2024 WeiXiaojing | 友情链接
    • 跟随系统
    • 浅色模式
    • 深色模式
    • 阅读模式