TS似乎将默认参数签名T = SomeType
解释为T extends any = SomeType
。编译器不能(选择不?(隐式键入T
到SomeType
,就像对文字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
关键字的方式构造它。
您可以在文档中阅读有关通用约束的内容。