Skip to content

Latest commit

 

History

History
86 lines (66 loc) · 2.17 KB

泛型约束.md

File metadata and controls

86 lines (66 loc) · 2.17 KB

泛型约束

必须谨慎使用类型变量,参考下面的例子:

// 定义泛型函数
function getLength<T>(arg: T): number {
  // 错误,编译器不知道类型变量T是否包含属性length,默认为不存在
  // error TS2339: Property 'length' does not exist on type 'T'
  return arg.length;
}

上例中没有任何地方表明 T 类型的参数 arg 包含属性 length,因而编译器认为不存在属性 length 报错。为了改正上述代码,需要约束类型变量 T 必须包含属性 length

语法

类型变量 extends 类型

类型约束关键字为 extends,和继承关键字一样。实际上,类型约束跟继承同义,类型变量继承了被约束类型的所有成员

// 声明接口
interface WithLength {
  length: number;
}

// 正确,T现在被接口类型WithLength约束,包含属性 length
function getLength<T extends WithLength>(arg: T): number {
  return arg.length;
}

默认类型

参考下面的例子:

interface MyType<T> {
  value: T;
}

// error TS2314: Generic type 'MyType<T>' requires 1 type argument(s)
let a: MyType = {
  value: "hello world"
}

泛型在使用的时候必须用实际类型取代类型参数,假如同上面那样,编译器就无法判定a.value的实际类型是什么(有可能是任何类型),因而报错。修正这个错误很简单,只需要在使用的时候传递类型参数即可:

// 正确
let a: MyType<string> = {
  value: "hello world"
}

每次都用尖括号语法注解确实挺烦的,尤其是在有些情况下,其他人使用 MyType 接口的时候可能并不知道这是一个泛型接口声明。TypeScript提供了默认类型语法:

类型变量 = 类型

参考下面的例子:

interface MyType<T = string> {
  value: T;
}

// 正确,在类型参数没有显示指定的情况下,采用了默认类型 string
let x1: MyType = {
  value: "hello world"
}
// 等价于
let x1: MyType<string> = {
  value: "hello world"
}

// 错误, error TS2322: Type 'number' is not assignable to type 'string'
let x2: MyType = {
  value: 123
}