索引签名参数类型不能为联合类型。考虑改用映射对象类型


130

我正在尝试使用以下模式:

enum Option {
  ONE = 'one',
  TWO = 'two',
  THREE = 'three'
}

interface OptionRequirement {
  someBool: boolean;
  someString: string;
}

interface OptionRequirements {
  [key: Option]: OptionRequirement;
}

这对我来说似乎很简单,但是出现以下错误:

索引签名参数类型不能为联合类型。考虑改用映射对象类型。

我究竟做错了什么?


1
的类型key只能是字符串,数字或符号。枚举不是。
工会

Answers:


193

您可以使用TS“ in”运算符,并执行以下操作:

enum Options {
  ONE = 'one',
  TWO = 'two',
  THREE = 'three',
}
interface OptionRequirement {
  someBool: boolean;
  someString: string;
}
type OptionRequirements = {
  [key in Options]: OptionRequirement; // Note that "key in".
}

7
嗯,这不编译吗?所述打字稿操场说:“在一个界面,一种计算机属性名必须引用其类型为一个文本类型或‘唯一的符号’类型的表达式。”
meriton

19
更改interface OptionRequirementstype OptionRequirements
Tyler Rick

4
这实际上对我不起作用:接口中的计算属性名称必须引用其类型为文字类型或“唯一符号”类型的
表达式

您能否告诉我们您使用的是哪个版本的Typescript?
Nacho Justicia Ramos

2
我已编辑此答案以使用映射的类型别名而不是接口。原始答案无法在我见过的任何版本的TypeScript下编译,并且当然也不会在当前版本的TypeScript(截至2020年8月为4.0)下编译。@NachoJusticiaRamos,如果您可以证明您的原始版本在某些版本的TypeScript上确实可以在某处使用,那么我很乐意还原所做的编辑,并提供您需要使用的环境描述。干杯!
jcalz

65

最简单的解决方案是使用 Record

type OptionRequirements = Record<Options, OptionRequirement>

您也可以自己实现为:

type OptionRequirements = {
  [key in Options]: OptionRequirement;
}

此构造仅可用于type,但不能使用interface

定义中的问题是说接口的键应该是type Options,这里Options是一个枚举,而不是字符串,数字或符号。

key in Options“为这是在联合类型选择那些特定的键”的意思。

type别名比别名更灵活和强大interface

如果你的类型并不需要在课堂上使用,选择typeinterface


7

我有一些类似的问题,但是我的情况是接口中的另一个字段属性,所以我的解决方案作为一个示例,带有可选的字段属性和键枚举:

export enum ACTION_INSTANCE_KEY {
  cat = 'cat',
  dog = 'dog',
  cow = 'cow',
  book = 'book'
}

type ActionInstances = {
  [key in ACTION_INSTANCE_KEY]?: number; // cat id/dog id/cow id/ etc // <== optional
};

export interface EventAnalyticsAction extends ActionInstances { // <== need to be extended
  marker: EVENT_ANALYTIC_ACTION_TYPE; // <== if you wanna add another field to interface
}

5

代替使用接口,使用映射的对象类型

enum Option {
  ONE = 'one',
  TWO = 'two',
  THREE = 'three'
}

type OptionKeys = keyof typeof Option;

interface OptionRequirement {
  someBool: boolean;
  someString: string;
}

type OptionRequirements = {                 // note type, not interface
  [key in OptionKeys]: OptionRequirement;   // key in
}

3

就我而言,我需要这些属性是可选的,因此我创建了此泛型类型。

type PartialRecord<K extends string | number | symbol, T> = { [P in K]?: T; };

然后这样使用它:

type MyTypes = 'TYPE_A' | 'TYPE_B' | 'TYPE_C';

interface IContent {
    name: string;
    age: number;
}

interface IExample {
    type: string;
    partials: PartialRecord<MyTypes, IContent>;
}

const example : IExample = {
    type: 'some-type',
    partials: {
        TYPE_A : {
            name: 'name',
            age: 30
        },
        TYPE_C : {
            name: 'another name',
            age: 50
        }
    }
}

0

我有一个类似的问题。创建角度形式验证器时,我尝试仅使用特定键。

export enum FormErrorEnum {
  unknown = 'unknown',
  customError = 'customError',
}

export type FormError = keyof typeof FormErrorEnum;

以及用法:

static customFunction(param: number, param2: string): ValidatorFn {
  return (control: AbstractControl): { [key: FormErrorEnum]?: any } => {
    return { customError: {param, param2} };
  };
}

这将允许使用1-X个键。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.