Làm cách nào để tôi có thể xác định giao diện cho một mảng đối tượng với Typecript?


113

Tôi có giao diện và mã sau đây. Tôi nghĩ rằng tôi đã làm đúng các định nghĩa nhưng tôi gặp lỗi:

interface IenumServiceGetOrderBy { id: number; label: string; key: any }[];

và:

getOrderBy = (entity): IenumServiceGetOrderBy => {
        var result: IenumServiceGetOrderBy;
        switch (entity) {
            case "content":
                result =
                [
                    { id: 0, label: 'CId', key: 'contentId' },
                    { id: 1, label: 'Modified By', key: 'modifiedBy' },
                    { id: 2, label: 'Modified Date', key: 'modified' },
                    { id: 3, label: 'Status', key: 'contentStatusId' },
                    { id: 4, label: 'Status > Type', key: ['contentStatusId', 'contentTypeId'] },
                    { id: 5, label: 'Title', key: 'title' },
                    { id: 6, label: 'Type', key: 'contentTypeId' },
                    { id: 7, label: 'Type > Status', key: ['contentTypeId', 'contentStatusId'] }
                ];
                break;
        }
        return result;
    };

Lỗi:

Error   190 Cannot convert '{}[]' to 'IenumServiceGetOrderBy':
    Type '{}[]' is missing property 'id' from type 'IenumServiceGetOrderBy'

Câu trả lời:


100

Bạn có thể xác định giao diện bằng trình chỉ mục :

interface EnumServiceGetOrderBy {
    [index: number]: { id: number; label: string; key: any };
}

32
Không thực sự là một "giao diện cho một mảng của các đối tượng với nguyên cảo"
basarat

Có, ví dụ của bạn về việc xác định giao diện chỉ cho các mục cụ thể sẽ là một cách hữu ích hơn để làm điều đó. Sẽ khá hiếm khi có một mảng các mục, nhưng không muốn tham chiếu một cách thuận tiện đến một mục duy nhất. Sử dụng một mảng thực cũng làm lộ .length trên giao diện, có thể sẽ được sử dụng khá thường xuyên.
Douglas

Làm thế nào để xác định lớp để impliment giao diện này?
alexey

18
Vấn đề với giải pháp này là đây không phải là một Arraygiao diện, do đó tất cả các Arraythuộc tính và phương thức như lengthhoặc pushsẽ bị thiếu.
Norman Breau

215

Bạn không cần sử dụng trình chỉ mục (vì nó ít an toàn hơn một chút). Bạn có hai lựa chọn:

interface EnumServiceItem {
    id: number; label: string; key: any
}

interface EnumServiceItems extends Array<EnumServiceItem>{}


// Option A 
var result: EnumServiceItem[] = [
    { id: 0, label: 'CId', key: 'contentId' },
    { id: 1, label: 'Modified By', key: 'modifiedBy' },
    { id: 2, label: 'Modified Date', key: 'modified' },
    { id: 3, label: 'Status', key: 'contentStatusId' },
    { id: 4, label: 'Status > Type', key: ['contentStatusId', 'contentTypeId'] },
    { id: 5, label: 'Title', key: 'title' },
    { id: 6, label: 'Type', key: 'contentTypeId' },
    { id: 7, label: 'Type > Status', key: ['contentTypeId', 'contentStatusId'] }
];

// Option B
var result: EnumServiceItems = [
    { id: 0, label: 'CId', key: 'contentId' },
    { id: 1, label: 'Modified By', key: 'modifiedBy' },
    { id: 2, label: 'Modified Date', key: 'modified' },
    { id: 3, label: 'Status', key: 'contentStatusId' },
    { id: 4, label: 'Status > Type', key: ['contentStatusId', 'contentTypeId'] },
    { id: 5, label: 'Title', key: 'title' },
    { id: 6, label: 'Type', key: 'contentTypeId' },
    { id: 7, label: 'Type > Status', key: ['contentTypeId', 'contentStatusId'] }
]

Cá nhân tôi đề xuất Tùy chọn A (di chuyển đơn giản hơn khi bạn đang sử dụng các lớp không phải giao diện).


3
Là thêm ?vào tất cả các khai báo trong giao diện, ví dụ. id?: number; label?: string; key?: anycách tốt nhất để tránh sự cố truyền nếu bạn sử dụng ít thuộc tính hơn những gì được xác định trong giao diện? I E. Tôi có thể không chỉ định keytrong thiết lập mảng đã nhập.
GONeale

Tùy chọn B hữu ích vì nó cho phép bạn sử dụng giao diện trong khi soạn các giao diện cấp cao hơn.
aashtonk

1
Geezus christ điều này đã làm phiền tôi rất lâu, cảm ơn bạn!
Matthew Harwood

2
Việc kê khai giao diện thứ hai cung cấp cho các lỗi tslint sau: " một giao diện tuyên bố không có thành viên tương đương với siêu kiểu của nó "
Inigo

2
Tôi có thể gợi ý rằng 'key' thuộc loại chuỗi không | string [] thay vì bất kỳ. Như thế này: interface EnumServiceItem { id: number; label: string; key: string | string[] }
JulianG

74

Bạn có thể xác định một giao diện dưới dạng mảng chỉ cần mở rộng giao diện Mảng.

export interface MyInterface extends Array<MyType> { }

Với điều này, bất kỳ đối tượng nào thực hiện MyInterfaceý muốn cần thực hiện tất cả các lệnh gọi hàm của mảng và chỉ có thể lưu trữ các đối tượng có MyTypekiểu.


6
Giải pháp đẹp. Đây phải là câu trả lời được chấp nhận.
demisx

1
Tại sao không sử dụng kiểu ( type MyTypeArray = Array<MyType>) thay vì mở rộng giao diện?
Pau Fracés

OP hỏi cho giao diện, tôi giả sử nó được mở rộng với các thuộc tính và các phương pháp khác, bạn không thể làm điều đó với một loại và cũng có thể loại được nhiều hạn chế so với một giao diện về khả năng sử dụng chung
NoNameProvided

@NoNameProvided "loại bị hạn chế hơn giao diện về khả năng sử dụng chung" Bạn có thể cung cấp thêm chi tiết về tuyên bố này không? Hạn chế của việc sử dụng kiểu so với giao diện là gì?
Pau Fracés

1
Giải pháp tốt nhất hơn những người khác nên có câu trả lời được chấp nhận
Andres Felipe

16

Tùy chọn bổ sung dễ dàng:

    interface simpleInt {
        id: number;
        label: string;
        key: any;
    }

    type simpleType = simpleInt[];

6

Không được dùng

interface EnumServiceGetOrderBy {
    [index: number]: { id: number; label: string; key: any };
}

Bạn sẽ gặp lỗi đối với tất cả các thuộc tính và phương thức của Mảng chẳng hạn như mối nối, v.v.

Giải pháp là tạo một giao diện xác định một mảng của giao diện khác (sẽ xác định đối tượng)

Ví dụ:

interface TopCategoriesProps {
  data: Array<Type>;
}
interface Type {
  category: string;
  percentage: number;
}

4

Trong Angular sử dụng 'mở rộng' để xác định giao diện cho 'Mảng' của các đối tượng.

Việc sử dụng một trình chỉ mục sẽ mang lại cho bạn một lỗi vì nó không phải là một giao diện Mảng nên không chứa các thuộc tính và phương thức.

ví dụ

lỗi TS2339: Thuộc tính 'find' không tồn tại trên loại 'ISelectOptions2'.

// good    
export interface ISelectOptions1 extends Array<ISelectOption> {}

// bad
export interface ISelectOptions2 {
    [index: number]: ISelectOption;
}

interface ISelectOption {
    prop1: string;
    prop2?: boolean;
}

Phương thức này sẽ dẫn đến "Giao diện khai báo không có thành viên nào tương đương với siêu kiểu của nó" nếu linter không cho phép giao diện trống.
demisx

Câu trả lời này đã kết thúc nó đã giúp tôi giải quyết vấn đề của mình! Đối với đối tượng ban đầu mà bạn muốn tạo một mảng trong một giao diện khác, bạn nhập "interface ISelectOptions {name1: type; name2: type;}, sau đó trong giao diện BIG của bạn, khi bạn đến khóa bạn muốn trở thành một mảng kiểu đó, keyZ: ISelectOptions []; sau đó khi bạn tạo JSON, myVar: BIG = {key1: val1, key2: val2,…, keyZ: [{name1: valA, name2: valB}, {name1: valC, name2 : valD}] đã hoạt động như một nhà vô địch! (tuy nhiên, không cần phải mở rộng lớp Array) Cảm ơn!
AppDreamer

3

Ngoài ra bạn có thể làm điều này.

            interface IenumServiceGetOrderBy {
                id: number; 
                label: string; 
                key: any;
            }

            // notice i am not using the []
            var oneResult: IenumServiceGetOrderBy = { id: 0, label: 'CId', key: 'contentId'};

            //notice i am using []
            // it is read like "array of IenumServiceGetOrderBy"
            var ArrayOfResult: IenumServiceGetOrderBy[] = 
            [
                { id: 0, label: 'CId', key: 'contentId' },
                { id: 1, label: 'Modified By', key: 'modifiedBy' },
                { id: 2, label: 'Modified Date', key: 'modified' },
                { id: 3, label: 'Status', key: 'contentStatusId' },
                { id: 4, label: 'Status > Type', key: ['contentStatusId', 'contentTypeId'] },
                { id: 5, label: 'Title', key: 'title' },
                { id: 6, label: 'Type', key: 'contentTypeId' },
                { id: 7, label: 'Type > Status', key: ['contentTypeId', 'contentStatusId'] }
            ];

2

Tùy chọn dễ dàng không có lỗi tslint ...

export interface MyItem {
    id: number
    name: string
}

export type MyItemList = [MyItem]

4
Các xuất khẩu MyItemListloại sẽ là "một mảng một yếu tố MyItem"
NoNameProvided

5
Có thể được export type MyItemList = MyItem[]không ?. IMO sự kết hợp của một giao diện và một loại bí danh là phù hợp nhất cho trường hợp này kể từ khi bạn có tất cả các phương pháp của các loại Array trong alias loại của bạn
Pau Fracés

2

Đây là phiên bản nội tuyến nếu bạn không muốn tạo một kiểu hoàn toàn mới:

export interface ISomeInterface extends Array<{
    [someindex: string]: number;
}> { };

0

Lập trình rất đơn giản. Sử dụng usecase đơn giản:

interface IenumServiceGetOrderBy { id: number; label: string; key: any }
 // OR
interface IenumServiceGetOrderBy { id: number; label: string; key: string | string[] }

// use interface like
const result: IenumServiceGetOrderBy[] = 
                [
                    { id: 0, label: 'CId', key: 'contentId' },
                    { id: 1, label: 'Modified By', key: 'modifiedBy' },
                    { id: 4, label: 'Status > Type', key: ['contentStatusId', 'contentTypeId'] }
                ];

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.