想象一下这个类描述了一个由作为其属性之一的键引用的对象存储:
class Store<T, K extends keyof T> {
readonly key: K;
readonly items: Map<T[K], T> = new Map();
constructor(key: K) {
this.key = key;
}
put(item: T) {
this.items.set(item[this.key], item);
}
get(key: T[K]): T | undefined {
return this.items.get(key);
}
}
为了使示例更具体,假设我们要保留两种类型的数据Store
:s:
interface Person {
name: string;
address: string;
}
interface Product {
id: number;
name: string;
category: string;
}
const personStore = new Store<Person, 'name'>('name'); // Stores Persons indexable by their name
const productStore = new Store<Product, 'id'>('id'); // Stores Products indexable by their id
personStore.put({name: 'Homer Simpson', address: '742 Evergreen Terrace'})
const homer = personStore.get('Homer Simpson');
productStore.put({id: 42, name: 'Pizza', category: 'Food'});
const pizza = productStore.get(42);
这可行,但令我困扰的是在创作时,Store
:s 必须声明用作键的属性两次 - 一次作为类型参数,一次作为文字值。
现在,可以从给定的参数值推断类型参数,但在这种情况下,T
不是参数的一部分,因此必须将其声明为类型参数。K
, 然而is构造函数参数的类型,以便可以推断它。但似乎无法推断K
同时陈述T
?
如果我完全省略类型参数,T
被推断为never
,给出了一个无用的对象,并且在构造过程中也出现了错误:
const someStore = new Store('name'); // Gives "argument of type name is not assignable to never"
我想要的是能够做到这一点:
const personStore = new Store<Person>('name'); // T is Person, name is keyof Person.
我考虑过声明一个构造函数接口,但这没有帮助。创建静态工厂方法可以返回完全类型化的通用对象,但也无法指定T
从中推断 Kkey
.
我显然也不想仅仅为了推断而在构造函数中提供虚拟项T
.
So: 是否有可能在声明另一种泛型类型的同时从参数推断出另一种泛型类型?或者有一些聪明的解决方法吗?