如何在类中动态添加属性,以便打字稿中的实例可以访问它们?

时间:2019-09-17 11:17:41

标签: typescript

我试图编写一个通用的工厂函数来创建自定义枚举对象,但是实例无法获得正确的属性。

这是地址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 具有正确的类型,以便我可以正确地访问构造函数中声明的属性(CommonStatusNORMAL)。

1 个答案:

答案 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>的值,它们的作用与您想要的版本相同。类型FactoryFactory<K>_Factory<K>的{​​{3}},因此类型Record<K, number>的对象同时具有Factory<K>和{{1} }中的config属性,以及options中的数值属性。

让我们看看它是否有效:

_Factory<K>

对我很好。好的,希望能有所帮助;祝你好运!

intersection