Kiểu tham số chữ ký chỉ mục không được là kiểu liên hợp. Thay vào đó, hãy cân nhắc sử dụng một loại đối tượng được ánh xạ


104

Tôi đang cố gắng sử dụng mẫu sau:

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

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

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

Điều này có vẻ rất đơn giản với tôi, tuy nhiên tôi gặp lỗi sau:

Kiểu tham số chữ ký chỉ mục không được là kiểu liên hợp. Thay vào đó, hãy cân nhắc sử dụng loại đối tượng được ánh xạ.

Tôi đang làm gì sai?


1
Loại keychỉ có thể là chuỗi, số hoặc ký hiệu. enum không.
unional

Câu trả lời:


160

Bạn có thể sử dụng toán tử TS "in" và thực hiện điều này:

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

5
Erm, cái này không biên dịch? Các nguyên cảo sân chơi cho biết : "Một tên thuộc tính trong một giao diện phải tham khảo một biểu thức mà type là một kiểu chữ hoặc một 'biểu tượng độc đáo' loại."
Meriton

19
Đổi interface OptionRequirementsthànhtype OptionRequirements
Tyler Rick

3
điều này thực sự không làm việc cho tôi: Một tính tên thuộc tính trong một giao diện phải tham khảo một biểu thức mà type là một kiểu chữ hoặc một 'biểu tượng độc đáo' loại
Tyguy7

Bạn có thể vui lòng cho chúng tôi biết bạn đang sử dụng phiên bản Typecript nào không?
Nacho Justicia Ramos

2
Tôi đã chỉnh sửa câu trả lời này để sử dụng bí danh loại được ánh xạ thay vì giao diện. Câu trả lời ban đầu không biên dịch theo bất kỳ phiên bản TypeScript nào mà tôi đã thấy và chắc chắn không biên dịch theo phiên bản TypeScript hiện tại (4.0 kể từ tháng 8 năm 2020). @NachoJusticiaRamos, nếu bạn có thể chứng minh rằng phiên bản gốc của bạn thực sự hoạt động ở một nơi nào đó, trong một số phiên bản TypeScript, thì tôi rất vui khi hoàn nguyên bản chỉnh sửa, cùng với mô tả về môi trường bạn cần sử dụng để nó hoạt động. Chúc mừng!
jcalz

58

Giải pháp đơn giản nhất là sử dụng Record

type OptionRequirements = Record<Options, OptionRequirement>

Bạn cũng có thể tự triển khai nó như:

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

Cấu trúc này chỉ có sẵn cho type, nhưng không interface.

Vấn đề trong định nghĩa của bạn là khóa giao diện của bạn phải là loại Options, đâu Optionslà enum, không phải là một chuỗi, số hoặc ký hiệu.

key in Optionsnghĩa là "đối với những khóa cụ thể nằm trong Tùy chọn loại liên hợp".

typebí danh linh hoạt và mạnh mẽ hơn interface.

Nếu loại của bạn không cần sử dụng trong lớp, hãy chọn typequa interface.


5

Tôi đã gặp một số vấn đề tương tự nhưng trường hợp của tôi là với một thuộc tính trường khác trong giao diện, vì vậy giải pháp của tôi như một ví dụ với thuộc tính trường tùy chọn với một enum cho khóa:

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
}

4

Thay vì sử dụng giao diện, hãy sử dụng loại đối tượng được ánh xạ

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
}

1

Trong trường hợp của tôi, tôi cần các thuộc tính là tùy chọn, vì vậy tôi đã tạo kiểu chung này.

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

Sau đó, sử dụng nó như vậy:

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

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

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

Thí dụ

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

0

Tôi đã có một vấn đề tương tự. Tôi đã cố gắng chỉ sử dụng các khóa cụ thể khi tạo trình xác thực dạng góc.

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

export type FormError = keyof typeof FormErrorEnum;

Và cách sử dụng:

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

Điều này sẽ cho phép 1 - X số khóa được sử dụng.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.