Home

TS中泛型<T>的使用

# 泛型

是指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型的一种特性。与any相比,使用泛型的优势是会保留参数类型。

# 为什么需要泛型

例如有一个identity函数, 这个函数会返回任何传入它的值。

function identity(arg: number): number {
    return arg;
}

如上,如果使用基本变量的话。那么只能规定一种变量来作为值类型。或者,我们使用any类型来定义函数:

function identity(arg: any): any {
    return arg;
}

我们要求传入的类型和返回的类型相同,any是任何类型,就无法达到要求。

# 泛型语法

function identity <T>(arg:T) : T {
  return arg
}

# 调用

let result = identity<string>("myString");
let result = identity<number>(1);

明确的指定了T的类型,并做为一个参数传给函数,使用了<>括起来。

通常我们利用类型推论-即编译器会根据传入的参数自动地帮助我们确定T的类型:

let result = identity("myString");  // type of result will be 'string'

# 泛型变量

现在假设我们向函数传入泛型T,返回T类型的数组

function loggingIdentity<T>(arg: T): T[] {
  let list:T[] = []
  for(let i = 0; i < 3; i++){
      list.push(arg)
  }
  return list

}

此处的T作为一个变量,当做类型的一部分使用,而不是整个类型,增加了灵活性。

# 泛型约束

定义一个接口来描述约束条件。使用这个接口和extends关键字来实现约束。

比如我们定义传入的参数类型,一定有某个属性

interface Lengthwise {
    length: number;
}

function loggingIdentity<T extends Lengthwise>(arg: T): T {
    console.log(arg.length);  // Now we know it has a .length property, so no more error
    return arg;
}

执行

loggingIdentity({length: 10, value: 3});

# 泛型接口

定义接口的时候,我们也可以使用泛型

interface A<T> {
  data: T
}

const Info: A<string> = {data: '1'}
console.log(Info.data) // "1"

# 泛型类

泛型也可以定义类

class clacArray<T>{
  private arr: T[] = [];

  add(value: T) {
      this.arr.push(value)
  }
  getValue(): T {
      let res = this.arr[0];
      console.log(this.arr)
      return res;
  }
}

const res = new clacArray()
res.add(1)
res.add(2)
res.add(3)

res.getValue() //[1, 2, 3] 
console.log(res.getValue) // 1

# 泛型常用字母

  • T:代表Type,定义泛型时通常用作第一个类型变量名称
  • K:代表Key,表示对象中的键类型;
  • V:代表Value,表示对象中的值类型;
  • E:代表Element,表示的元素类型;

# Pick

将某个类型中的子属性挑出来,变成包含这个类型部分属性的子类型。

interface Props {
  name: string,
  age: number,
  sex: boolean
}

type nameProps = Pick<Props, 'name' | 'age'>

const info: nameProps = {
  name: '小杜杜',
  age: 7
}

从上述代码上来看, Props原本属性包括name、age、sex三个属性,通过 Pick我们吧name和age挑了出来,所以不需要sex属性

# Exclude

作用:将T类型中的U类型剔除。Exclude语法:Exclude<T, U>

// 数字类型
type numProps = Exclude<1 | 2 | 3, 1 | 2> // 3
type numProps1 = Exclude<1, 1 | 2> // nerver
type numProps2 = Exclude<1, 1> // nerver
type numProps3 = Exclude<1 | 2, 7> // 1 2

// 字符串类型
type info = "name" | "age" | "sex"
type info1 = "name" | "age" 
type infoProps = Exclude<info, info1> //  "sex"

使用

type A = string | number | boolean
type B = string | boolean | symbol
type C = string

type exc = Exclude<A, B>
// type exc = number

type exc2 = Exclude<A, C>
// type exc2 = number | boolean

# Extra

作用:将T 可分配给的类型中提取 U。与 Exclude相反,Extra语法:Extra<T, U>

  type numProps = Extract<1 | 2 | 3, 1 | 2> // 1 | 2

# Omit

Omit<T, K> 的主要功能在于,从一个已有的对象类型 T 中排除指定的属性 K,进而创建一个新的对象类型

interface Props {
  name: string,
  age: number,
  sex: boolean
}

type Props2 = Omit(Props, "sex")  // { name: string, age: number}

Exclude 和 Omit 的主要区别在于它们处理类型的方式和侧重点,Exclude 是针对联合类型,用于排除一些特定成员类型,Omit 是针对对象类型,用于忽略或排除某些特定属性;