Как я могу определить интерфейс для массива объектов с помощью Typescript?


115

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

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

35
Не совсем «интерфейс для массива объектов с Typescript»
— basarat

Да, ваш пример определения интерфейса только для определенных элементов был бы более полезным способом сделать это. Было бы довольно редко иметь массив элементов, но не хотелось бы удобно ссылаться на один элемент. Использование реального массива также предоставляет .length в интерфейсе, который, вероятно, будет использоваться довольно часто.
— Дуглас

Как определить класс для реализации этого интерфейса?
— Алексей

19
Проблема с этим решением заключается в том, что это не Arrayинтерфейс, поэтому все Arrayсвойства и методы, такие как lengthили, pushбудут отсутствовать.
— Norman

220

Ты не нужно использовать индексатор (так как он немного менее безопасен). У вас есть два варианта:

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

Лично я рекомендую вариант A (более простая миграция, когда вы используете классы, а не интерфейсы).


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

Вариант B полезен, поскольку он позволяет использовать интерфейс при составлении интерфейсов более высокого уровня.
— Ааштонк

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

2
Второе объявление интерфейса дает следующую ошибку tslint: « интерфейс, не объявляющий членов, эквивалентен его супертипу »
— Иниго

2
Могу я предположить, что «ключ» имеет тип строки | string [] вместо любого. Как это: interface EnumServiceItem { id: number; label: string; key: string | string[] }
— JulianG 06

79

Вы можете определить интерфейс как массив, просто расширив интерфейс Array.

export interface MyInterface extends Array<MyType> { }

При этом любой объект, который реализует это MyInterface, должен будет реализовать все вызовы функций массивов и сможет хранить только объекты с этим MyTypeтипом.


6
Красивое решение. Это должен быть принятый ответ.
— demisx 01

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

OP запросил интерфейс, я предполагаю, что он расширен другими свойствами и методами, вы не можете сделать это с типом, а также тип более ограничен, чем интерфейсы, с точки зрения общего удобства использования
— NoNameProvided 06

@NoNameProvided "тип более ограничен, чем интерфейсы с точки зрения общего удобства использования". Вы можете подробнее рассказать об этом заявлении? Каковы ограничения использования типов по сравнению с интерфейсами?
— Pau Fracés

1
Лучшим решением, чем другие, должен быть принятый ответ
— Андрес Фелипе


8

Не используй

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

Вы получите ошибки для всех свойств и методов массивов, таких как splice и т. Д.

Решение состоит в том, чтобы создать интерфейс, который определяет массив другого интерфейса (который будет определять объект).

Например:

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

4

В Angular используйте extends для определения интерфейса для «массива» объектов.

Использование индексатора приведет к ошибке, поскольку это не интерфейс Array, поэтому он не содержит свойств и методов.

например

ошибка TS2339: свойство «найти» не существует для типа «ISelectOptions2».

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

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

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

Этот метод приведет к тому, что «интерфейс, объявляющий отсутствие членов, эквивалентен его супертипу», если линтер не разрешает пустые интерфейсы.
— demisx

Этот ответ был так близок, что помог мне решить мою проблему! Для начального объекта, для которого вы хотите создать массив в другом интерфейсе, вы набираете "interface ISelectOptions {name1: type; name2: type;} затем в вашем БОЛЬШОМ интерфейсе, когда вы дойдете до ключа, который хотите быть массивом этот тип 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]

5
Экспортированный MyItemListтип будет «одноэлементным массивом из MyItem»
— NoNameProvided

5
Может быть export type MyItemList = MyItem[]? ИМО, комбинация интерфейса и псевдонима типа лучше всего подходит для этого случая, поскольку у вас есть все методы типа Array в псевдониме типа
— 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'] }
                ];


0

Вот одно решение, адаптированное к вашему примеру:

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

interface IenumServiceGetOrderBy extends Array<IenumServiceGetOrderByAttributes> {

}
let result: IenumServiceGetOrderBy;

С помощью этого решения вы можете использовать все свойства и методы массива (например: length, push(), pop(), splice()...)

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.