TypeScript 中带有泛型的默认参数

use*_*406 10 typescript

考虑 TypeScript 文档中泛型的最后一个示例: https://www.typescriptlang.org/docs/handbook/generics.html#using-class-types-in-generics

如果我想设置Lion默认值createInstance()我该怎么做?

例如:

class Animal {
  numLegs: number = 0;
}

class Lion extends Animal {
  keeper = "zookeeper";
}

function createInstance<A extends Animal>(c: new () => A = Lion): A { // error!
// -------------------------------------> ~~~~~~~~~~~~~~~~~~~~~
//  'Lion' is assignable to the constraint of type 'A', but 'A' could be 
// instantiated with a different subtype of constraint 'Animal'.
  return new c();
}
Run Code Online (Sandbox Code Playgroud)

游乐场链接

jca*_*alz 7

目前还没有办法通过编译器验证的类型安全来做到这一点。有关相关功能请求,请参阅microsoft/TypeScript#56315 。目前所有的方法都涉及解决这个限制。


您可以使用泛型参数默认值类型断言来告诉编译器缺乏推断意味着is A,并且可以做出该假设:ALion

function createInstanceAssert<A extends Animal = Lion>(c: new () => A = Lion as any) {
  return new c();
}
Run Code Online (Sandbox Code Playgroud)

我认为这将在您的用例中按需要工作:

createInstanceAssert(Lion).keeper.nametag;
createInstanceAssert(Bee).keeper.hasMask;
createInstanceAssert().keeper.nametag;
Run Code Online (Sandbox Code Playgroud)

尽管有人可能手动指定通用参数并造成麻烦:

createInstanceAssert<Bee>().keeper.hasMask.valueOf(); // compiles, but error at runtime
// ---------------> ~~~~~ don't do this, okay?
Run Code Online (Sandbox Code Playgroud)

这可能不太可能,但您应该意识到这一点。


如果您确实想防止误用,可以使用重载来区分两个单独的用例:

function createInstanceOverload<A extends Animal>(c: new () => A): A;
function createInstanceOverload(): Lion;
function createInstanceOverload(c: new () => Animal = Lion) {
  return new c();
}
Run Code Online (Sandbox Code Playgroud)

您基本上可以使用参数调用它,在这种情况下它是通用的并且A是推断的,或者您可以不带参数调用它,在这种情况下它不是通用的,并且Lion出现:

createInstanceOverload(Lion).keeper.nametag;
createInstanceOverload(Bee).keeper.hasMask;
createInstanceOverload().keeper.nametag;
Run Code Online (Sandbox Code Playgroud)

由于没有通用的零参数调用签名,因此在没有大编译器错误的情况下不再可能执行以下操作:

createInstanceOverload<Bee>().keeper.hasMask.valueOf(); // error at compile time
Run Code Online (Sandbox Code Playgroud)

Playground 代码链接