我试着使用下面的模式:

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

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

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

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

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

我做错了什么?


当前回答

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

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
}

其他回答

在我的例子中:

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

我有一些类似的问题,但我的情况是在接口的另一个字段属性,所以我的解决方案作为一个可选字段属性的例子,有一个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
}

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

编辑

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

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

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

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

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

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

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

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
}