インデックスシグニチャパラメータタイプを共用体タイプにすることはできません。代わりに、マップされたオブジェクトタイプの使用を検討してください


129

次のパターンを使用しようとしています。

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

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

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

これは私には非常に簡単に思えますが、次のエラーが発生します。

インデックスシグニチャパラメータタイプを共用体タイプにすることはできません。代わりに、マップされたオブジェクトタイプの使用を検討してください。

私は何が間違っているのですか?


1
のタイプはkey、文字列、数値、または記号のみです。列挙型はそうではありません。
unional

回答:


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
えーと、これはコンパイルされませんか?活字体遊び場言う:「インタフェースで計算されたプロパティ名は、そのタイプのリテラルタイプかのユニークなシンボル」タイプである式を参照しなければなりません。」
メリトン

19
変更interface OptionRequirementstype OptionRequirements
タイラーリック

4
これは実際に私のために動作しません:Aは、そのタイプのリテラルタイプかのユニークなシンボル」タイプである式を参照しなければならないインターフェイスでプロパティ名を計算
Tyguy7

使用しているTypescriptのバージョンを教えてください。
ナチョジャスティシアラモス

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

定義の問題は、インターフェイスのキーがタイプOptionsである必要があることです。ここOptionsで、は文字列、数値、記号ではなく列挙型です。

key in Options「union型のオプションでありますそれらの特定のキーのための」手段。

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個のキーを使用できるようになります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.