我有一个保存项目列表的类,但不是将它们保存在一个平面数组中,而是将它们保存在一个对象映射中,其中每个属性代表一组项目。就像我们有一个汽车清单,我们会按制造商对它们进行分组。
// object map
interface IObjectMap<TValue> {
[key: string]: TValue;
}
// object map; same as interface but build using keys union type
type ItemMap<TMapKeys extends keyof IObjectMap<unknown>, TValue> = Record<TMapKeys, TValue[]>;
// just a function taking one parameter and returning a result
type GetterFunc<TInput, TResult> = (item: TInput) => TResult;
// object map where the value type of properties are getter functions returning a string
type GetterMap<TMapKeys extends keyof IObjectMap<unknown>, TInput> = Record<TMapKeys, GetterFunc<TInput, string>>;
class GroupedItems<
TItem, // item type
TGroupKeys extends keyof IObjectMap<unknown> // object map keys
> {
public groups: ItemMap<TGroupKeys, TItem> = {} as ItemMap<TGroupKeys, TItem>;
public countryGetters: GetterMap<TGroupKeys, TItem> = {} as GetterMap<TGroupKeys, TItem>;
public addItems(items: TItem[], getGroupKey: GetterFunc<TItem, TGroupKeys>): void {
this.items.concat(items);
this.items
.forEach(item => {
let name = getGroupKey(item);
if (this.groups[name] === undefined) {
// create placeholder for items
this.groups[name] = [];
}
// Put the item in the group
this.groups[name].push(item);
});
}
public assignGetters(getters: GetterMap<TGroupKeys, TItem>) {
this.countryGetters= getters;
}
}
该类有两个泛型类型参数:
- 我们将分组的项目类型(即
Car
) - 组键(即
'renault' | 'peugeot' | ...
)
然后类成员都被定义为对象映射:
groups
将项目保留在组数组中countryGetters
也是一个与项目组具有相同属性的对象映射,但它们定义了一个函数,该函数返回传入的汽车的制造商国家
使用示例
上面的代码似乎没有错误,但随着它的使用,类型似乎没有得到应有的解析。当我尝试使用未在映射或联合类型的组键中定义的项目组名称时,我希望编译器/linter 抱怨...
interface Car {
model: string;
year: number;
}
interface CarMakers<TValue> extends IObjectMap<TValue> {
renault: TValue;
peugeot: TValue;
}
let select = new GroupedItems<
Car,
keyof CarMakers<unknown>
>();
select.addItems([
{ model: 'R5', year: 1980, dummy: false }, // error; correct
{ model: '206', year: 2004 },
{ model: '3008', year: 2010 }
],
car =>
car.year < 2000
? 'audi' // should be an error; "audi" not in "keyof MakerGroups<>"
: 'peugeot'
);
select.assignGetters({
renault: () => 'France',
audi: () => 'Germany' // should be an error; "audi" not in "keyof MakerGroups<>"
});
如您所见,Typescript 没有解析组名,所以我的类型定义不够严格(我想),因此我可以无效地操作不存在的组。从编译时的角度来看,上面的代码似乎很好,但应该为我做检查,intellisense 应该帮助我填写组名。