Comment puis-je définir une interface pour un tableau d'objets avec Typescript?


115

J'ai l'interface et le code suivants. Je pensais que je faisais les définitions correctement mais j'obtiens une erreur:

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

et:

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

Erreur:

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

Réponses:


101

Vous pouvez définir une interface avec un indexeur :

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

33
Pas vraiment une "interface pour un tableau d'objets avec Typescript"
— basarat

Oui, votre exemple de définition d'une interface uniquement pour les éléments particuliers serait un moyen plus utile de le faire. Il serait assez rare d'avoir un tableau d'éléments, mais ne pas vouloir référencer facilement un seul élément. L'utilisation d'un tableau réel expose également .length sur l'interface, qui sera probablement utilisée assez souvent.
— Douglas

Comment définir une classe pour implémenter cette interface?
— alexey

18
Le problème avec cette solution est qu'il ne s'agit pas d'une Arrayinterface, donc toutes les Arraypropriétés et méthodes telles que lengthou pushseront manquantes.
— Norman Breau

217

Vous n'avez pas besoin d'utiliser un indexeur (car il est un peu moins sécurisé). Vous avez deux options:

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

Personnellement, je recommande l'option A (migration plus simple lorsque vous utilisez des classes et non des interfaces).


3
Ajoute ?à toutes les déclarations dans l'interface, par exemple. id?: number; label?: string; key?: anyle meilleur moyen d'éviter un problème de diffusion si vous utilisez moins de propriétés que ce qui est défini dans l'interface? C'est à dire. Je ne peux pas spécifier keydans la configuration du tableau typé.
— GONeale

L'option B est utile car elle vous permet d'utiliser l'interface tout en composant des interfaces de niveau supérieur.
— aashtonk

1
Geezus christ, cela m'a dérangé pendant si longtemps merci!
— Matthew Harwood

2
La deuxième déclaration d'interface donne l'erreur tslint suivante: " une interface ne déclarant aucun membre équivaut à son supertype "
— Inigo

2
Puis-je suggérer que «clé» est de type chaîne | string [] au lieu de tout. Comme ça: interface EnumServiceItem { id: number; label: string; key: string | string[] }
— JulianG

75

Vous pouvez définir une interface en tant que tableau en étendant simplement l'interface Array.

export interface MyInterface extends Array<MyType> { }

Avec cela, tout objet qui implémente le MyInterfacedevra implémenter tous les appels de fonction des tableaux et ne pourra stocker que des objets avec le MyTypetype.


6
Belle solution. Cela devrait être la réponse acceptée.
— demisx

2
Pourquoi ne pas utiliser un type ( type MyTypeArray = Array<MyType>) au lieu d'étendre une interface?
— Pau Fracés

OP a demandé une interface, je suppose qu'elle est étendue avec d'autres propriétés et méthodes, vous ne pouvez pas le faire avec un type et le type est également plus limité qu'une interface en termes de convivialité générale
— NoNameProvided

@NoNameProvided "le type est plus limité qu'une interface en termes de convivialité générale" Pouvez-vous fournir plus de détails sur cette déclaration? Quelles sont les limites de l'utilisation des types par rapport aux interfaces?
— Pau Fracés

1
La meilleure solution que d'autres devrait être la réponse acceptée
— Andres Felipe

16

Option facile supplémentaire:

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

    type simpleType = simpleInt[];

6

Ne pas utiliser

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

Vous obtiendrez des erreurs pour toutes les propriétés et méthodes des tableaux telles que l'épissure, etc.

La solution est de créer une interface qui définit un tableau d'une autre interface (qui définira l'objet)

Par exemple:

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

4

Dans Angular, utilisez «extend» pour définir l'interface d'un «tableau» d'objets.

L'utilisation d'un indexeur vous donnera une erreur car ce n'est pas une interface Array et ne contient donc pas les propriétés et les méthodes.

par exemple

erreur TS2339: la propriété 'find' n'existe pas sur le type 'ISelectOptions2'.

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

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

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

Cette méthode se traduira par "Une interface ne déclarant aucun membre équivaut à son supertype" si le linter n'autorise pas les interfaces vides.
— demisx du

Cette réponse était tellement proche qu'elle m'a aidé à résoudre mon problème! Pour l'objet initial pour lequel vous souhaitez créer un tableau dans une autre interface, vous tapez "interface ISelectOptions {nom1: type; nom2: type;} puis dans votre BIG interface, lorsque vous arrivez à la clé que vous voulez être un tableau de ce type, keyZ: ISelectOptions []; puis lorsque vous créez le JSON, myVar: BIG = {key1: val1, key2: val2,…, keyZ: [{name1: valA, name2: valB}, {name1: valC, name2 : valD}] a fonctionné comme un champion! (pas besoin d'étendre la classe Array, cependant) Merci!
— AppDreamer

3

Vous pouvez également le faire.

            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

Option facile sans erreurs tslint ...

export interface MyItem {
    id: number
    name: string
}

export type MyItemList = [MyItem]

5
Le MyItemListtype exporté sera "un tableau à un élément de MyItem"
— NoName Fourni

5
Serait-ce possible export type MyItemList = MyItem[]?. IMO, la combinaison d'une interface et d'un alias de type est la meilleure solution pour ce cas puisque vous avez toutes les méthodes du type Array dans votre alias de type
— Pau Fracés

2

Voici une version en ligne si vous ne souhaitez pas créer un tout nouveau type:

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

0

La programmation est simple. Utilisez un cas d'utilisation 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'] }
                ];

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.