我试图编写一个通用的工厂函数来创建自定义枚举对象,但是实例无法获得正确的属性。
这是地址https://stackblitz.com/edit/typescript-rkl1zr
的在线预览环境
打字稿3.6.2
这是我的代码:
version: '2'
services:
app:
image: my-application:latest
tty: true
volumes_from:
- configs:ro
configs:
build:
context: .
args:
env: $ENV
tty: true
volumes:
- /configs
我希望type IConfig<T> = {
[key in keyof T]: IOption
}
export interface IOption {
value: number
label: string
}
class Factory<T> {
[key: keyof T]: any // An index signature parameter type must be 'string' or 'number'.
config: IConfig<T>
options: IOption[]
constructor(config: IConfig<T>) {
this.options = []
this.config = config
for (let key in config) {
this.options.push(config[key])
this[key] = config[key].value // Type 'number' is not assignable to type 'this[Extract<keyof T, string>]'.
}
}
}
const data = {
NORMAL: {
value: 1,
label: 'NORMAL'
},
ABNORMAL: {
value: 0,
label: 'ABNORMAL',
},
}
const CommonStatus = new Factory<typeof data>(data)
CommonStatus.NORMAL // No Intelligent Tips
具有正确的类型,以便我可以正确地访问构造函数中声明的属性(CommonStatus
和NORMAL
)。
答案 0 :(得分:1)
使用已发布的代码,我不确定如果只看T
,为什么还要关心keyof T
……T
的属性值类型始终被忽略,因此您可能不需要Factory
类型来携带它们。因此,我将其更改为Record
Factory<T>
,而不是Factory<K extends string>
,将其更改为IConfig<T>
。如果您的用例关心<K, IOption>
的值类型,则可以保留其原始方式。它不会影响其余答案。
不幸的是,这里没有一个简单且完全类型安全的解决方案。即使使用classes extending arbitrary generic types,TypeScript也不支持mixins。您只能扩展其键为静态的类型,而T[keyof T]
之类的情况仅是动态已知的,情况并非如此。
您可以做的是使用在类实现中使用type assertions的东西来弥补在K
中缺乏任意键的能力,然后使用进一步的类型声明来产生一个用户可以访问的类的版本,其行为与您想要的方式相同。
在这里:
this
因此,我将class _Factory<K extends string> {
config: Record<K, IOption>;
options: IOption[];
constructor(config: Record<K, IOption>) {
this.options = [];
this.config = config;
for (let key in config) {
this.options.push(config[key]);
this[key as keyof this] = config[key].value as any; // assertion
}
}
}
type Factory<K extends string> = _Factory<K> & Record<K, number>;
const Factory = _Factory as new <K extends string>(
config: Record<K, IOption>
) => Factory<K>;
重命名为Factory<K>
,甚至没有尝试使用动态键。在构造函数内部,对_Factory<K>
属性的分配具有许多类型断言,以防止编译器抱怨。
此后,我们有一个名为this
的类型和一个名为Factory<K>
的值,它们的作用与您想要的版本相同。类型Factory
是Factory<K>
与_Factory<K>
的{{3}},因此类型Record<K, number>
的对象同时具有Factory<K>
和{{1} }中的config
属性,以及options
中的数值属性。
让我们看看它是否有效:
_Factory<K>
对我很好。好的,希望能有所帮助;祝你好运!