我有一个通用类型E
。它是诸如Customer
,Product
,Todo
等的Entity实例。具有两个可配置字段id
和guid
,但是不必将其命名为。这两个属性的名称是可配置的。
这是一个实体的示例:
class Todo {
id: string;
gid: string;
title: string;
completed: boolean;
}
为了配置属性名称,使用了这样的配置类:
/**
* Store configuration.
*/
export class StoreConfig {
idKey?:string ='id';
guidKey?:string ='gid';
}
StoreConfig用于确定分配了生成ID的类型E
的实例上属性的名称。所以我们有这样的方法:
/**
* Post (Add a new) element to the store.
* @param e
*/
post(e: E) {
const guid: string = v1();
e[this.config.guid] = guid;
this.entries[guid] = e;
打字稿抛出:
[ts]元素隐式地具有“ any”类型,因为类型“ {}”没有索引签名 (属性)EStore.config:StoreConfig
是否可以解决此问题?这是个小把戏,因为E
类型具有两个属性,整体名称是可配置的...?
该类本质上也有两个索引签名。一个用于id
属性(还没有命名/它是可配置的),另一个是guid
属性(还没有命名/它是可配置的)...
如果我这样做:
(<any>e)[this.config.guidKey] = guid;
Typescript不会抱怨,但是我想知道是否有一种更优雅的方式来声明它?
答案 0 :(得分:1)
You'll need type parameters for the names of the two properties. (Well, since the properties have the same type string
, you could use a single type parameter with a union type, but that's a hack IMO.) Then you can use a mapped type to declare the actual properties.
interface StoreConfig<I extends string, G extends string> {
idKey: I;
guidKey: G;
}
type EntityBase<I extends string, G extends string> =
// TODO: In TypeScript 3.1, change to the following for elegance:
//{[P in I]: string} & {[P in G]: string}
{[P in I | G]: string};
class Store<I extends string, G extends string, E extends EntityBase<I, G>> {
constructor(private config: StoreConfig<I, G>) {}
entries: {[guid: string]: E};
post(e: E) {
const guid: string = v1();
e[this.config.guidKey] = guid;
this.entries[guid] = e;
}
}
// https://github.com/Microsoft/TypeScript/issues/10571 will make this nicer.
new Store<"id", "gid", Todo>({idKey: "id", guidKey: "gid"});