angular - typescript 构造函数 : accept string for enum

标签 angular typescript

我正在使用 TypeScript 为 Angular 中的模型定义构造函数。模型中的一个属性被设置为具有一些可能的字符串值的枚举。如果我将一个枚举值传递给构造函数,这就可以正常工作。 问题是我需要根据 API 响应调用构造函数,该 API 响应返回需要映射到该属性的值的字符串。

有没有办法将字符串(只要它是枚举中定义的值之一)传递给构造函数?

枚举:

export enum TestTypes {
    FIRST = 'first',
    SECOND = 'second',
}

export class Test {
    this.myType: TestTypes;

    constructor(options: {type: TestTypes}) {
        this.myType = options.type;
    }
}

以下作品 const a = new Test({type:TestTypes.FIRST});

我想实现的目标: const b = new Test({type:'first'})

我应该执行以下操作吗? const b = new Test({type:TestTypes['first']})

最佳答案

最简单的方法是将您的 enum 更改为像这样的直接字典:

const literal = <L extends string | number | boolean>(l: L) => l;

export const TestTypes = {
  FIRST: literal('first'),
  SECOND: literal('second'),
};

export type TestTypes = (typeof TestTypes)[keyof typeof TestTypes]

literal() 函数是一个帮助程序,它提示编译器解释值 as a string literal 而不是扩大到 string

现在,值 TestTypes.FIRST 就是字符串 "first" ,值 TestTypes.SECOND 就是字符串 "second" ,类型 TestTypes 就是联合 "first"|"second" 。这可以让您的类(class)按预期工作:

export class Test {
  myType: TestTypes; // this is an annotation, not an initializer, right?

  constructor(options: { type: TestTypes }) {
    // options.type, not type  
    this.myType = options.type;
  }
}

const a = new Test({ type: TestTypes.FIRST }); // okay
const b = new Test({ type: "first" }); // okay... it's the same thing

如果你想将 TestTypes 保留为 enum ,你可以得到你想要的,但在我看来这太过分了。

首先,如果您想要一个接受 enum 或正确的 string 值的独立函数,您可以像这样创建一个 generic function:

declare function acceptTestTypesOrString<E extends string>(
  k: E & (Extract<TestTypes, E> extends never ? never : E)
): void;

我不知道是否应该对此进行解释,但它利用了 TestTypes.FIRST extends "first" 等事实。让我们看看它是否有效:

acceptTestTypesOrString(TestTypes.FIRST) // okay
acceptTestTypesOrString(TestTypes.SECOND) // okay
acceptTestTypesOrString("first") // okay
acceptTestTypesOrString("second") // okay
acceptTestTypesOrString("third") // error

看起来不错。但是您希望将其作为构造函数。而你 can't make a constructor function generic 。相反,您可以使整个类通用,如下所示:

export class Test<E extends string> {
  myType: E; // this is an annotation, not an initializer, right?

  constructor(options: { 
    type: E & (Extract<TestTypes, E> extends never ? never : E) 
  }) {
    // options.type, not type  
    this.myType = options.type;
  }
}

const a = new Test({ type: TestTypes.FIRST }); // okay
const b = new Test({ type: "first" }); // also okay

在这种情况下,a 将是 Test<TestTypes.FIRST> 类型,而 b 将是 Test<"first"> 类型。它们大部分是可以互换的,但是当您只希望构造函数使用通用类型时,为整个类拖拽通用类型似乎不是最佳选择。

但它有效。


好的,希望其中一个想法对您有所帮助。祝你好运!

关于angular - typescript 构造函数 : accept string for enum,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51433319/

相关文章:

javascript - 尽管我的组件已在我的模块的 entryComponents 选项中声明,但 Angular 如何找不到该组件的组件工厂?

Angular Material - 在页面加载/html 标签上嵌入日期选择器

angular - FormControl.detectchanges - 为什么使用 distinctUntilChanged?

typescript - Typescript 中的 nameof 关键字

javascript - RxJS 6 获取 Observable 数组的过滤列表

typescript - Vue 3 检测不到对在 Vue 组件外部创建的对象所做的更改

javascript - 动画化动态 Angular 组件的移除?

javascript - ngx-translate 和 ngx-i18next 有什么区别

angular - 如何从我的 json 中获取单个值? Angular 5/ typescript

reactjs - 如何解决 Typescript 错误——mapbox-gl 和 React hooks