TypeScript 泛型的使用形式

193 阅读3分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第10天,点击查看活动详情

泛型使用中相关词语概念

泛型也是一种类型,所以也可以用在类,函数、接口等上面,其实泛型的使用和函数使用基本一样,都有形参实参,比如在函数中使用的泛型T就叫形参:形式类型参数,是抽象的并不是实际的类型,在调用的时候传的参数就叫做实参:实际类型参数,是具体的一个类型,当然也可以不是一个具体类型,也可能是形参,这种是嵌套调用的情况下,比如调用的泛型函数是在另一个泛型函数中并且实参是这个函数的形参。当前和函数还一样,形参可以定义默认值,<T = string>,如果在调用的时候不传递实参就使用默认值类型,这种就叫做可选类型参数,可选类型参数在定义的时候要放到后面, 后面的类、接口等都是这种形式的使用。 image.png

泛型约束 extends

是对形参的约束,定义在形参上,就是让实参不能随便乱传,要有一些约束,使用的是extends关键词,我们理解的时候可以和继承一样的思考,如下代码中U extends Person表明U(Student)类型它是Person的子类型但是并一定不等于Person类型, U(Student)类型的属性可能比Person类型属性多,你直接返回一个满足Person类型的对象,但是它是不对的,会导致后续使用推断中它有这个name属性,但是实质上没有,会导致一系列错误问题。

interface Person { id: string };
interface Student { id: string, name: string };

function getInfo<T, U extends Person>(id: T, obj: U): U {
  // return { id: '1' }; // 错误 
  return obj;
}
getInfo<string, Student>('1', { id: '1', name: '小明' })

泛型函数

泛型形参定义在函数名后面,可以在函数的参数和返回值以及函数体中都可以使用该泛型。

function getName<T>(name:T): T[] {
  const dt: Array<T> = [name];
  return dt;
}

// 函数表达式中使用放到function后面
const getName1 = function<T>(name:T): T[] {
  const dt: Array<T> = [name];
  return dt;
}

箭头函数中使用泛型

// 普通箭头函数定义方式
const getname1 = (name: string): string =>{
  return name;
}
const getname2: (name: string) => string = (name) =>{
  return name;
}
// 泛型箭头函数定义方式,当泛型形参只有一个时要后面加一个逗号。
const getname3 = <T,>(name: T): T =>{
  return name;
}
// 当有泛型约束时可以不写逗号。
const getname4 = <T extends string>(name: T): T =>{
  return name;
}
// 
const getname5 = <T, U>(name: T, age: U): T =>{
  return name;
}
const getname6: <T,>(name: T) => T = (name) =>{
  return name;
}

泛型接口

一样定义在接口名称后面,可以在接口内部使用也可以在接口的继承类上使用。

interface Student<T> extends Person<T> {
  name: T;
  age: T | undefined;
}
const stu: Student<string> = { name: '11', id: '1' }

泛型类

形参定义在类的名称后面, 可以在类的继承类上使用或者实现接口上使用,可以在类的内部都可以使用,但是不能在类的静态成员上使用,因为泛型类中的类型其实质都是作用于类的实例上,而静态方法并不在类的实例上。

class Student<T, U> extends Child<T> implements Person<T, U> {
  // staitc displayName = function(name: T) {} // 错误,不能在静态成员中使用
  constructor(public name: T) {
    super(name)
  }
  getName(): U {
    ...
  }
}

const stu = new Student<string, string>('小明')

泛型类型别名

形参定义在类型别名后面,可以在等号后面使用, 泛型类型别名用出特别广泛,比如许多内置的泛型工具都是如此定义的将一堆泛型表达式定义成泛型类型别名, 如Partial, Exclude<T, U>等等。我们也可以定义项目中常用到的类型别名。

type Nullable<T> = T | undefined | null;
const name: Nullable<string> = null;