默认参数:<T = SomeType> vs <T 扩展 SomeType = SomeType>?



TS似乎将默认参数签名T = SomeType解释为T extends any = SomeType。编译器不能(选择不?(隐式键入TSomeType,就像对文字let s = "string, not any!"一样。为什么不呢?

下面是一个示例场景。该代码在<T extends SomeType = SomeType>(扩展+默认(中按原样工作,但在<T = SomeType>(默认参数(中失败。额外的extends SomeType在做什么工作?

示例场景

CCD_ 9子类按商店名称作为字典(type Stores = Record<string, Store>(注册在CCD_。Registry.getStore应仅接受已注册的存储名称作为其name参数。(游乐场(

abstract class Store {
private registry: Registry;
public addToRegistry(registry: Registry) {
this.registry = registry;
}
}
class UserStore extends Store {}
class ListStore extends Store {}
type Stores = Record<string, Store>
//class Registry<T = Stores> {
//class Registry<T extends Stores> {
class Registry<T extends Stores = Stores> {
stores: T;
constructor(stores: T) {
Object.values(stores).forEach((store) => {
store.addToRegistry(this);
});
this.stores = stores;
}
// 'name' should only accept registered store names
public getStore(name: keyof T): Store {
return this.stores[name];
}
}
// dummy test instances
const users = new UserStore();
const list = new ListStore();
const registry = new Registry({ users, list });
// compiler should acccpt
const goodStore = registry.getStore('users');
// compiler should reject
const badStore = registry.getStore('not-a-registered-store');

class Registry<T extends Stores = Stores>[扩展+默认]

class Registry<T = Stores>【默认参数】

  • ❌构造函数中的store的类型为any
  • getStore存在编译器错误T[keyof T]' is not assignable to type 'Store'
  • 我先尝试了一下,希望它能起作用。嘿,TS,默认情况下T等于存储字典
  • 似乎没有T extends Stores = Stores那么多余

我缺少什么?

给定一个泛型类,接收一个泛型类型T。这意味着,您可以传递任何给定的类型,例如数字、字符串、对象、Foo等。

class Registry<T> { /* ... */ }

合格操作的子集随后受到限制。根据您的示例,gettergetStore不仅仅在T上可用。

强制Registry只接受Stores类型必须使用extends关键字。这告诉编译器,只期望符合给定类型的类型(称为泛型约束(。例如:T extends string,则符合以下条件:Registry<"someString">Registry<string>等等

因此,T extends Stores现在需要一个商店。您可以将此存储作为默认类型传递,这将导致:T extends Stores = Store或者,您可以在实例化注册表时提供此泛型。

这意味着,以下是您的解决方案:

class Registry<T extends Stores = Stores>

p.S:你也可以省略默认的= Stores,因为它不是必需的。TypeScript可以推断出这一点。

class Registry<T extends Stores> { /* ... */ }
// ...
const registry = new Registry({ users, list });
const goodStore = registry.getStore('users');

回答您关于let s = "some string"的问题。是的,TypeScript确实将其键入为string。但是,请记住,它是一个变量,一旦设置了s的类型,就不能给它分配一个数字,比如:

let s = "some string";
s = 5; // ❌ causes type error: number is not assignable to string

而泛型可以是任何期望的东西,除非按照您希望它是extends关键字的方式构造它。

您可以在文档中阅读有关通用约束的内容。

最新更新