Jenis parameter tanda tangan indeks tidak boleh merupakan jenis gabungan. Pertimbangkan untuk menggunakan tipe objek yang dipetakan sebagai gantinya

130

Saya mencoba menggunakan pola berikut:

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

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

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

Ini tampaknya sangat mudah bagi saya, namun saya mendapatkan kesalahan berikut:

Jenis parameter tanda tangan indeks tidak boleh merupakan jenis gabungan. Pertimbangkan untuk menggunakan tipe objek yang dipetakan sebagai gantinya.

Apa yang saya lakukan salah?

john maccarthy
sumber
1
Jenis keyhanya dapat berupa string, angka atau simbol. enum tidak.
unional

Jawaban:

193

Anda dapat menggunakan operator TS "dalam" dan melakukan ini:

enum Options {
  ONE = 'one',
  TWO = 'two',
  THREE = 'three',
}
interface OptionRequirement {
  someBool: boolean;
  someString: string;
}
type OptionRequirements = {
  [key in Options]: OptionRequirement; // Note that "key in".
}
Nacho Justicia Ramos
sumber
7
Erm, ini tidak bisa dikompilasi? The naskah taman bermain mengatakan : "Sebuah nama properti dihitung dalam sebuah antarmuka harus mengacu pada ekspresi yang tipe adalah tipe literal atau jenis 'simbol unik'."
meriton
19
Ubah interface OptionRequirementsketype OptionRequirements
Tyler Rick
4
ini sebenarnya tidak berfungsi untuk saya: Nama properti yang dihitung dalam sebuah antarmuka harus merujuk ke ekspresi yang tipenya adalah tipe literal atau tipe 'simbol unik'
Tyguy7
Bisakah Anda memberi tahu kami versi Typecript yang Anda gunakan?
Nacho Justicia Ramos
2
Saya telah mengedit jawaban ini untuk menggunakan alias tipe yang dipetakan alih-alih antarmuka. Jawaban asli tidak dapat dikompilasi di bawah versi TypeScript apa pun yang pernah saya lihat, dan tentu saja tidak dikompilasi di bawah versi TypeScript saat ini (4.0 pada Agustus 2020). @NachoJusticiaRamos, jika Anda dapat mendemonstrasikan bahwa versi asli Anda benar-benar berfungsi di suatu tempat, dalam beberapa versi TypeScript, saya akan dengan senang hati mengembalikan hasil edit, bersama dengan deskripsi lingkungan yang perlu Anda gunakan agar berfungsi. Bersulang!
jcalz
65

Solusi paling sederhana adalah menggunakan Record

type OptionRequirements = Record<Options, OptionRequirement>

Anda juga dapat menerapkannya sendiri sebagai:

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

Konstruksi ini hanya tersedia untuk type, tetapi tidak interface.

Masalah dalam definisi Anda mengatakan kunci antarmuka Anda harus bertipe Options, di mana Optionsenum, bukan string, angka, atau simbol.

The key in Optionsberarti "untuk orang-orang kunci tertentu yang ada di tipe serikat Options".

typealias lebih fleksibel dan bertenaga dari interface.

Jika jenis Anda tidak perlu digunakan di kelas, memilih typelebih interface.

unional
sumber
7

Saya memiliki beberapa masalah serupa tetapi kasus saya adalah dengan properti bidang lain di antarmuka jadi solusi saya sebagai contoh dengan properti bidang opsional dengan enum untuk kunci:

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
}
Kurkov Igor
sumber
5

Alih-alih menggunakan antarmuka, gunakan tipe objek yang dipetakan

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
}
Stefan
sumber
3

Dalam kasus saya, saya membutuhkan properti menjadi opsional, jadi saya membuat tipe generik ini.

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

Kemudian gunakan seperti itu:

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

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

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

Contoh

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

Saya memiliki masalah serupa. Saya mencoba menggunakan hanya kunci tertentu saat membuat validator bentuk sudut.

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

export type FormError = keyof typeof FormErrorEnum;

Dan penggunaannya:

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

Ini akan memungkinkan 1 - X jumlah kunci untuk digunakan.

Mempertanyakan
sumber