¿Cómo puedo definir una interfaz para una matriz de objetos con Typecript?


113

Tengo la siguiente interfaz y código. Pensé que estaba haciendo las definiciones correctamente pero recibo un error:

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

y:

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:

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

Respuestas:


100

Puede definir una interfaz con un indexador :

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

32
No es realmente una "interfaz para una serie de objetos con Typecript"
— basarat

Sí, su ejemplo de definir una interfaz solo para los elementos particulares sería una forma más útil de hacerlo. Sería bastante raro tener una variedad de elementos, pero no quisiera hacer referencia a un solo elemento de manera conveniente. El uso de una matriz real también expone .length en la interfaz, que probablemente se usará con bastante frecuencia.
— Douglas

¿Cómo definir la clase para implementar esta interfaz?
— alexey

18
El problema con esta solución es que no se trata de una Arrayinterfaz, por lo tanto, faltarán todas las Arraypropiedades y métodos como lengtho push.
— Norman Breau

217

No es necesario utilizar un indexador (ya que es un poco menos seguro para los tipos). Tienes dos opciones:

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

Personalmente recomiendo la Opción A (migración más simple cuando está utilizando clases, no interfaces).


3
Se agrega ?a todas las declaraciones en la interfaz, por ejemplo. id?: number; label?: string; key?: any¿Cuál es la mejor manera de evitar un problema de transmisión si usa menos propiedades que las definidas en la interfaz? Es decir. Puede que no lo especifique keyen la configuración de matriz escrita.
— GONeale

La opción B es útil ya que le permite utilizar la interfaz mientras crea interfaces de nivel superior.
— aashtonk

1
Dios mío, esto me ha molestado durante tanto tiempo, ¡gracias!
— Matthew Harwood

2
La segunda declaración de interfaz da el siguiente error tslint: " una interfaz que no declara miembros es equivalente a su supertipo "
— Iñigo

2
¿Puedo sugerir que 'clave' es de tipo cadena | cadena [] en lugar de cualquiera. Así: interface EnumServiceItem { id: number; label: string; key: string | string[] }
— JulianG

74

Puede definir una interfaz como matriz simplemente extendiendo la interfaz de matriz.

export interface MyInterface extends Array<MyType> { }

Con esto, cualquier objeto que implemente el MyInterfacenecesitará implementar todas las llamadas a funciones de matrices y solo podrá almacenar objetos con el MyTypetipo.


6
Hermosa solución. Esta debería ser la respuesta aceptada.
— demisx

1
¿Por qué no usar un tipo ( type MyTypeArray = Array<MyType>) en lugar de extender una interfaz?
— Pau Fracés

OP solicitó la interfaz, supongo que se extiende con otras propiedades y métodos, no puede hacer eso con un tipo y también el tipo es más limitado que una interfaz en términos de usabilidad general
— NoNameProvided

@NoNameProvided "el tipo es más limitado que una interfaz en términos de usabilidad general" ¿Puede proporcionar más detalles sobre esta declaración? ¿Cuáles son las limitaciones del uso de tipos frente a interfaces?
— Pau Fracés

1
La mejor solución que otras debería ser la respuesta aceptada
— Andrés Felipe

16

Opción fácil adicional:

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

    type simpleType = simpleInt[];

6

No utilice

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

Obtendrá errores para todas las propiedades y métodos de las matrices, como empalme, etc.

La solución es crear una interfaz que defina una matriz de otra interfaz (que definirá el objeto)

Por ejemplo:

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

4

En Angular, use 'extiende' para definir la interfaz para una 'Matriz' de objetos.

El uso de un indexador le dará un error ya que no es una interfaz de matriz, por lo que no contiene las propiedades y los métodos.

p.ej

error TS2339: La propiedad 'buscar' no existe en el 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 dará como resultado "Una interfaz que declara que no hay miembros es equivalente a su supertipo" si el linter no permite interfaces vacías.
— demisx

¡Esta respuesta fue tan cercana que me ayudó a resolver mi problema! Para el objeto inicial para el que desea crear una matriz dentro de otra interfaz, escriba "interface ISelectOptions {name1: type; name2: type;} luego dentro de su interfaz GRANDE, cuando llegue a la clave que desea que sea una matriz de ese tipo, keyZ: ISelectOptions []; luego, cuando crea el JSON, myVar: BIG = {key1: val1, key2: val2,…, keyZ: [{name1: valA, name2: valB}, {name1: valC, name2 : valD}] funcionó como un campeón (aunque no necesitó extender la clase Array) ¡Gracias!
— AppDreamer

3

También puedes hacer esto.

            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

Opción fácil sin errores de tslint ...

export interface MyItem {
    id: number
    name: string
}

export type MyItemList = [MyItem]

4
El MyItemListtipo exportado será "una matriz de un elemento de MyItem"
— NoNameProvided

5
¿Puede ser export type MyItemList = MyItem[]? En mi opinión, la combinación de una interfaz y un alias de tipo es la mejor opción para este caso, ya que tiene todos los métodos del tipo Array en su alias de tipo
— Pau Fracés

2

Aquí hay una versión en línea si no desea crear un tipo completamente nuevo:

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

0

La programación es sencilla. Utilice un caso de uso simple:

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


Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.