Як я можу визначити інтерфейс для масиву об’єктів з Typescript?


114

У мене є наступний інтерфейс і код. Я думав, що я роблю визначення правильно, але я отримую помилку:

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

і:

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

Помилка:

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

Відповіді:


101

Ви можете визначити інтерфейс з індексатором :

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

33
Насправді не "інтерфейс для масиву об’єктів з
— Typescript

Так, ваш приклад визначення інтерфейсу лише для певних елементів був би більш корисним способом зробити це. Дуже рідко є масив елементів, але не хочеться зручно посилатися на один елемент. Використання реального масиву також виставляє .length на інтерфейс, який, ймовірно, буде використовуватися досить часто.
— Дуглас

Як визначити клас для застосування цього інтерфейсу?
— alexey

18
Проблема цього рішення полягає в тому, що це не Arrayінтерфейс, тому всі Arrayвластивості та методи, такі як lengthабо pushбудуть відсутні.
— Норман Бро

217

Не потрібно використовувати індексатор (оскільки це трохи менше typesafe). У вас є два варіанти:

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'] }
]

Особисто я рекомендую Варіант А (простіша міграція, коли Ви використовуєте класи, а не інтерфейси).


3
Додає ?до всіх декларацій в інтерфейсі, наприклад. id?: number; label?: string; key?: anyнайкращий спосіб уникнути проблеми кастингу, якщо ви використовуєте менше властивостей, ніж визначено в інтерфейсі? Тобто Я не можу вказати keyв налаштуваннях набраного масиву.
— GONeale

Варіант B корисний, оскільки дозволяє використовувати інтерфейс під час складання інтерфейсів вищого рівня.
— aashtonk

1
Боже, Христос, це мене набридло так чортово довго дякую!
— Меттью Харвуд

2
Друга декларація інтерфейсу дає таку помилку tslint: " інтерфейс, який оголошує жодних членів, не еквівалентний його супертипу "
— Inigo

2
Чи можу я припустити, що "ключ" - це тип рядка | string [] замість будь-якого. interface EnumServiceItem { id: number; label: string; key: string | string[] }
— Ось так

75

Ви можете визначити інтерфейс як масив, просто розширивши інтерфейс Array.

export interface MyInterface extends Array<MyType> { }

При цьому будь-який об’єкт, який реалізує MyInterfaceзаповіт, повинен реалізувати всі виклики функцій масивів і лише зможе зберігати об'єкти з MyTypeтипом.


6
Прекрасне рішення. Це має бути прийнятою відповіддю.
— demisx

2
Чому б не використовувати тип ( type MyTypeArray = Array<MyType>) замість розширення інтерфейсу?
— Pau Fracés

ОП запитав інтерфейс, я припускаю, що він розширений іншими властивостями та методами. Ви не можете цього робити з типом, а також тип є більш обмеженим, ніж інтерфейси з точки зору загальної зручності використання
— NoNameProvided

@NoNameProvided "Тип більш обмежений, ніж інтерфейси з точки зору загальної зручності використання". Чи можете ви надати більш детальну інформацію про це? Які обмеження щодо використання типів та інтерфейсів?
— Pau Fracés

1
Найкращим рішенням, ніж інші, має стати прийнята відповідь
— Андрес Феліпе

16

Додатковий простий варіант:

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

    type simpleType = simpleInt[];

6

Не використовувати

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

Ви отримаєте помилки для всіх властивостей і методів масивів, таких як зрощення тощо.

Рішення полягає у створенні інтерфейсу, який визначає масив іншого інтерфейсу (який визначатиме об’єкт)

Наприклад:

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

4

У кутовому використанні "розширюється" для визначення інтерфейсу для "масиву" об'єктів.

Використання індексатора дасть вам помилку, оскільки його інтерфейс не масив, тому не містить властивостей та методів.

напр

помилка TS2339: властивість 'find' не існує для типу 'ISelectOptions2'.

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

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

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

Цей метод призведе до того, що "інтерфейс, який оголошує відсутність членів, еквівалентний його супертипу", якщо лінійка не дозволяє порожні інтерфейси.
— demisx

Ця відповідь була так близька, що допомогла мені вирішити свою проблему! Для початкового об'єкта, для якого потрібно створити масив в іншому інтерфейсі, ви вводите "інтерфейс ISelectOptions {name1: type; name2: type;}, а потім у межах свого інтерфейсу BIG, коли ви дістанетесь до ключа, який ви хочете стати масивом. цей тип, keyZ: ISelectOptions []; тоді, коли ви створюєте JSON, myVar: BIG = {key1: val1, key2: val2,…, keyZ: [{name1: valA, name2: valB}, {name1: valC, name2 : valD}] працював як чемпіон! (не потрібно було продовжувати клас Array, хоча) Дякую!
— AppDreamer

3

Також ви можете це зробити.

            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

Простий варіант без помилок tslint ...

export interface MyItem {
    id: number
    name: string
}

export type MyItemList = [MyItem]

4
Експортований MyItemListтип буде "масивом з одним елементом MyItem"
— NoNameProvided

5
Може бути export type MyItemList = MyItem[]?. IMO, комбінація інтерфейсу та псевдоніма типу найкраще підходить для цього випадку, оскільки у вас є всі способи типу масиву у вашому псевдонімі типу
— Pau Fracés

2

Ось вбудована версія, якщо ви не хочете створювати абсолютно новий тип:

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

0

Програмування просте. Використовуйте просту футляр:

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.