Skip to content
Published at:

Generics 泛型

Generics 初探

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

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

// 泛型
function identity3<T>(arg: T): T {
  return arg;
}

// 第一种:传入所有的参数,包括类型参数
identity3<string>('hello');

// 第二种:类型参数推断
identity3('worlds');

使用泛型类型变量

ts
function identity4<Type>(arg: Type): Type {
  console.log(arg.length); // Error: T doesn't have .length
  return arg;
}

function identity5<Type>(arg: Type[]): Type[] {
  console.log(arg.length); // No error, since arg is an array
  return arg;
}

function identity6<Type>(arg: Array<Type>): Array<Type> {
  console.log(arg.length); // No error, since arg is an array
  return arg;
}

泛型类型

泛型接口

ts
interface GenericIdentityFn {
  <Type>(arg: Type): Type;
}

function identity<Type>(arg: Type): Type {
  return arg;
}

let myIdentity: GenericIdentityFn = identity;

将泛型参数作为整个接口的参数

ts
interface GenericIdentityFn<Type> {
  (arg: Type): Type;
}

function identity<Type>(arg: Type): Type {
  return arg;
}

let myIdentity: GenericIdentityFn<number> = identity;

泛型类

与接口类似

ts
class GenericNumber<NumType> {
  zeroValue: NumType;
  add: (x: NumType, y: NumType) => NumType;
  constructor() {}
  // constructor(zeroValue: NumType, add: (x: NumType, y: NumType) => NumType) {
  //   this.zeroValue = zeroValue;
  //   this.add = add;
  // }
}

let myGenericNumber = new GenericNumber<number>();
myGenericNumber.zeroValue = 0;
myGenericNumber.add = function (x: number, y: number) {
  return x + y;
};

let stringNumeric = new GenericNumber<string>();
stringNumeric.zeroValue = '';
stringNumeric.add = function (x: string, y: string) {
  return x + y;
};

泛型约束

使用extends关键字来表示我们的约束

ts
interface Lengthwise {
  length: number;
}

function loggingIdentity<Type extends Lengthwise>(arg: Type): Type {
  console.log(arg.length);
  return arg;
}

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

在泛型约束中使用类型参数

ts
function getProperty<Type, Key extends keyof Type>(arg: Type, key: Key) {
  return arg[key];
}

let x = { a: 1, b: 2, c: 3, d: 4 };

getProperty(x, 'a'); // OK
// getProperty(x, 'm'); // Error: Argument of type '"m"' is not

在泛型中使用类类型

通过构造函数引用类类型

ts
function create<Type>(c: { new (): Type }): Type {
  return new c();
}

更高级的示例: 使用原型属性来推断和约束构造函数和类类型的实例端之间的关系。

ts
class BeeKeeper {
  hasMask: boolean = true;
}

class ZooKeeper {
  nameTag: string = 'Mikle';
}

class Animal {
  numLegs: number = 4;
}

class Bee extends Animal {
  numLegs: number = 6;
  keeper: BeeKeeper = new BeeKeeper();
}

class Lion extends Animal {
  keeper: ZooKeeper = new ZooKeeper();
}

function createInstance<A extends Animal>(c: new () => A): A {
  return new c();
}

createInstance(Lion).keeper.nameTag;
createInstance(Bee).keeper.hasMask;

泛型参数默认值

ts
declare function create(): Container<HTMLDivElement, HTMLDivElement[]>;
declare function create<T extends HTMLElement>(): Container<T, T[]>;
declare function create<
  T extends HTMLElement,
  U extends HTMLElement[]
>(): Container<T, U>;

使用泛型默认参数来简化

ts
declare function create<
  T extends HTMLElement = HTMLDivElement,
  U extends HTMLElement[] = T[]
>(element?: T, children?: U): Container<T, U>;

const div = create();
const p = create(new HTMLParagraphElement());