Como posso definir uma interface para uma matriz de objetos com Typescript?


113

Tenho a seguinte interface e código. Achei que estava fazendo as definições corretamente, mas estou recebendo um erro:

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

e:

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

Erro:

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

Respostas:


100

Você pode definir uma interface com um indexador :

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

32
Não é realmente uma "interface para uma matriz de objetos com Typescript"
— basarat em

Sim, seu exemplo de definição de uma interface apenas para os itens específicos seria uma maneira mais útil de fazer isso. Seria muito raro ter uma matriz de itens, mas não querer referenciar convenientemente um único item. Usar um array real também expõe .length na interface, que provavelmente será usado com bastante frequência.
— Douglas

Como definir a classe para implementar esta interface?
— alexey

18
O problema com essa solução é que ela não é uma Arrayinterface, portanto, todas as Arraypropriedades e métodos como lengthou pushestarão ausentes.
— Norman Breau

216

Você não precisa usar um indexador (já que é um pouco menos seguro para tipos). Você tem duas opções:

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

Pessoalmente, eu recomendo a Opção A (migração mais simples quando você está usando classes, não interfaces).


3
Está adicionando ?a todas as declarações na interface, por exemplo. id?: number; label?: string; key?: anya melhor maneira de evitar um problema de fundição se você usar menos propriedades do que o que está definido na interface? Ou seja, Não posso especificar keyna configuração da matriz digitada.
— GONeale 01 de

A opção B é útil, pois permite que você use a interface enquanto compõe interfaces de nível superior.
— aashtonk

1
Jesus Cristo, isso me incomoda há tanto tempo, obrigado!
— Matthew Harwood de

2
A segunda declaração de interface fornece o seguinte erro tslint: " uma interface que não declara nenhum membro é equivalente a seu supertipo "
— Inigo

2
Posso sugerir que 'chave' é do tipo string | string [] em vez de qualquer. Assim: interface EnumServiceItem { id: number; label: string; key: string | string[] }
— JulianG

74

Você pode definir uma interface como array simplesmente estendendo a interface Array.

export interface MyInterface extends Array<MyType> { }

Com isso, qualquer objeto que implemente o MyInterfaceprecisará implementar todas as chamadas de função de arrays e somente poderá armazenar objetos com o MyTypetipo.


6
Bela solução. Esta deve ser a resposta aceita.
— demisx 01 de

1
Por que não usar um type ( type MyTypeArray = Array<MyType>) em vez de estender uma interface?
— Pau Fracés

OP pediu interface, suponho que seja estendida com outras propriedades e métodos, você não pode fazer isso com um tipo e também o tipo é mais limitado do que uma interface em termos de usabilidade geral
— NoName Fornecido em

@NoNameProvided "o tipo é mais limitado do que uma interface em termos de usabilidade geral" Você pode fornecer mais detalhes sobre esta declaração? Quais são as limitações do uso de tipos versus interfaces?
— Pau Fracés,

1
Melhor solução do que outras deve ser a resposta aceita
— Andres Felipe

16

Opção fácil adicional:

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

    type simpleType = simpleInt[];

6

Não use

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

Você obterá erros para todas as propriedades e métodos de Arrays, como splice etc.

A solução é criar uma interface que defina um array de outra interface (que definirá o objeto)

Por exemplo:

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

4

Em Angular, use 'extends' para definir a interface de um 'Array' de objetos.

Usar um indexador fornecerá um erro, pois não é uma interface Array, portanto, não contém as propriedades e métodos.

por exemplo

Erro TS2339: A propriedade 'localizar' não existe no tipo 'ISelectOptions2'.

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

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

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

Este método resultará em "Uma interface que não declara nenhum membro é equivalente ao seu supertipo" se o linter não permitir interfaces vazias.
— demisx

Essa resposta foi tãããão próxima que me ajudou a resolver meu problema! Para o objeto inicial para o qual você deseja criar um array dentro de outra interface, você digita "interface ISelectOptions {name1: type; name2: type;} então dentro de sua interface BIG, quando você chegar à chave que deseja ser um array de esse tipo, keyZ: ISelectOptions []; então, quando você cria o JSON, myVar: BIG = {key1: val1, key2: val2,…, keyZ: [{name1: valA, name2: valB}, {name1: valC, name2 : valD}] funcionou como um campeão! (não precisava estender a classe Array, no entanto) Obrigado!
— AppDreamer

3

Você também pode fazer isso.

            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

Opção fácil sem erros tslint ...

export interface MyItem {
    id: number
    name: string
}

export type MyItemList = [MyItem]

4
O MyItemListtipo exportado será "uma matriz de um elemento de MyItem"
— SemNome Fornecido em

5
Pode ser export type MyItemList = MyItem[]? IMO a combinação de uma interface e um alias de tipo é a melhor opção para este caso, já que você tem todos os métodos do tipo Array em seu alias de tipo
— Pau Fracés

2

Esta é uma versão embutida se você não quiser criar um tipo totalmente novo:

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

0

A programação é simples. Use um caso de uso simples:

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

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.