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

我试着使用下面的模式:

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


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


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

这对我来说似乎很简单,但是我得到了以下错误:

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

我做错了什么?

147564 次浏览

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

type OptionRequirements = Record<Options, OptionRequirement>

你也可以自己实现:

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

此构造只适用于type,而不适用于interface

定义中的问题是,接口的键应该是Options类型,其中Options是enum,而不是字符串、数字或符号。

key in Options表示“用于联合类型Options中的特定键”。

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

如果你的类型不需要在类中使用,选择type而不是interface

你可以用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".
}

我有一些类似的问题,但我的情况是在接口的另一个字段属性,所以我的解决方案作为一个例子,可选字段属性与一个enum键:

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
}

与其使用接口,不如使用映射对象类型

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
}

我也遇到过类似的问题。我试图在创建angular表单验证器时只使用特定的键。

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个键。

在我的例子中,我需要属性是可选的,所以我创建了这个泛型类型。

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
}
}
}

在我的例子中:

export type PossibleKeysType =
| 'userAgreement'
| 'privacy'
| 'people';


interface ProviderProps {
children: React.ReactNode;
items: {
//   ↙ this colon was issue
[key: PossibleKeysType]: Array<SectionItemsType>;
};
}

我通过使用in操作符而不是:来修复它

~~~


interface ProviderProps {
children: React.ReactNode;
items: {
//     ↙ use "in" operator
[key in PossibleKeysType]: Array<SectionItemsType>;
};
}

编辑

TL;DR:使用Record<type1,type2>或映射对象,例如:

type YourMapper = {
[key in YourEnum]: SomeType
}

我遇到了类似的问题,问题是键的允许类型是字符串,数字,符号或模板文字类型。

因此,正如Typescript所建议的,我们可以使用映射对象类型:

type Mapper = {
[key: string]: string;
}

注意,在map对象中,我们只允许使用字符串、数字或符号作为键,所以如果我们想使用特定的字符串(即emum或union类型),我们应该在索引签名中使用in关键字。这用于引用枚举或联合中的特定属性。

type EnumMapper = {
[key in SomeEnum]: AnotherType;
};
在一个真实的例子中,假设我们想要得到这个结果, 它的键和值都是指定类型的对象:

  const notificationMapper: TNotificationMapper = {
pending: {
status: EStatuses.PENDING,
title: `${ENotificationTitels.SENDING}...`,
message: 'loading message...',
},
success: {
status: EStatuses.SUCCESS,
title: ENotificationTitels.SUCCESS,
message: 'success message...',
},
error: {
status: EStatuses.ERROR,
title: ENotificationTitels.ERROR,
message: 'error message...'
},
};

为了用Typescript实现这一点,我们应该创建不同的类型,然后在Record<>或者使用映射对象类型:

export enum EStatuses {
PENDING = 'pending',
SUCCESS = 'success',
ERROR = 'error',
}


interface INotificationStatus {
status: string;
title: string;
message: string;
}


//option one, Record:
type TNotificationMapper = Record<EStatuses, INotificationStatus>


//option two. mapped object:
type TNotificationMapper = {
[key in EStatuses]:INotificationStatus;
}
interface OptionRequirements {
(key: Option): OptionRequirement;
}

这里我使用的是枚举,但这种方法对枚举和联合类型都适用。

< p > *注意: 类似的语法使用圆括号而不是方括号(即这个(...)而不是这个[...],可能不会显示任何错误,但它表示一个完全不同的东西,一个函数接口,所以这个:

interface Foo {
(arg:string):string;
}

实际上描述了一个函数签名,例如:

const foo = (arg:string) => string;