Wie kann ich mit Typescript eine Schnittstelle für ein Array von Objekten definieren?


112

Ich habe die folgende Schnittstelle und Code. Ich dachte, ich mache die Definitionen richtig, aber ich erhalte eine Fehlermeldung:

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

und:

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'

Antworten:


99

Sie können eine Schnittstelle mit einem Indexer definieren :

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

32
Nicht wirklich eine "Schnittstelle für ein Array von Objekten mit Typoskript"
— Basarat

Ja, Ihr Beispiel, eine Schnittstelle nur für bestimmte Elemente zu definieren, wäre eine nützlichere Methode. Es wäre ziemlich selten, eine Reihe von Elementen zu haben, aber nicht bequem auf ein einzelnes Element verweisen zu wollen. Die Verwendung eines realen Arrays macht auch die Länge der Schnittstelle sichtbar, was wahrscheinlich ziemlich häufig verwendet wird.
— Douglas

Wie definiere ich eine Klasse, um diese Schnittstelle zu implementieren?
— Alexey

18
Das Problem bei dieser Lösung ist, dass dies keine ArraySchnittstelle ist, daher fehlen alle ArrayEigenschaften und Methoden wie lengthoder pushwerden fehlen.
— Norman Breau

214

Sie müssen nicht brauchen einen Indexer zu verwenden (da es ein bisschen weniger typsicher). Sie haben zwei Möglichkeiten:

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

Persönlich empfehle ich Option A (einfachere Migration, wenn Sie Klassen und keine Schnittstellen verwenden).


3
Fügt ?zu allen Deklarationen in der Schnittstelle hinzu, z. id?: number; label?: string; key?: anyDer beste Weg, um ein Casting-Problem zu vermeiden, wenn Sie weniger Eigenschaften verwenden als in der Benutzeroberfläche definiert? Dh. Ich kann nicht keyim typisierten Array-Setup angeben .
— GONeale

Option B ist nützlich, da Sie damit die Schnittstelle verwenden können, während Sie Schnittstellen auf höherer Ebene erstellen.
— Aashtonk

1
Geezus Christus, das hat mich so verdammt lange gestört, danke!
— Matthew Harwood

2
Die zweite Schnittstellendeklaration gibt den folgenden tslint-Fehler aus: " Eine Schnittstelle, die keine Mitglieder deklariert, entspricht ihrem Supertyp "
— Inigo

2
Darf ich vorschlagen, dass 'key' vom Typ string | ist string [] statt any. So: interface EnumServiceItem { id: number; label: string; key: string | string[] }
— JulianG

74

Sie können eine Schnittstelle als Array definieren, indem Sie einfach die Array-Schnittstelle erweitern.

export interface MyInterface extends Array<MyType> { }

Damit muss jedes Objekt, das das MyInterfaceimplementiert, alle Funktionsaufrufe von Arrays implementieren und kann nur Objekte mit dem MyTypeTyp speichern .


6
Schöne Lösung. Dies sollte die akzeptierte Antwort sein.
— Demisx

1
Warum nicht einen type ( type MyTypeArray = Array<MyType>) verwenden, anstatt eine Schnittstelle zu erweitern?
— Pau Fracés

OP fragte nach Schnittstelle, ich nehme an, es ist mit anderen Eigenschaften und Methoden erweitert, Sie können das nicht mit einem Typ tun und auch Typ ist in Bezug auf die allgemeine Benutzerfreundlichkeit eingeschränkter als eine Schnittstelle
— NoNameProvided

@NoNameProvided "Der Typ ist in Bezug auf die allgemeine Benutzerfreundlichkeit eingeschränkter als eine Schnittstelle." Können Sie diese Aussage detaillierter beschreiben? Was sind die Einschränkungen bei der Verwendung von Typen gegenüber Schnittstellen?
— Pau Fracés

1
Beste Lösung als andere sollte die akzeptierte Antwort sein
— Andres Felipe

16

Zusätzliche einfache Option:

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

    type simpleType = simpleInt[];

4

Verwenden Sie im Winkel "Erweitert", um die Schnittstelle für ein "Array" von Objekten zu definieren.

Die Verwendung eines Indexers führt zu einem Fehler, da es sich nicht um eine Array-Schnittstelle handelt und daher keine Eigenschaften und Methoden enthält.

z.B

Fehler TS2339: Die Eigenschaft 'find' ist für den Typ 'ISelectOptions2' nicht vorhanden.

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

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

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

Diese Methode führt zu "Eine Schnittstelle, die erklärt, dass keine Mitglieder vorhanden sind, entspricht ihrem Supertyp", wenn der Linter keine leeren Schnittstellen zulässt.
— Demisx

Diese Antwort war soooo nah, dass sie mir half, mein Problem zu lösen! Für das ursprüngliche Objekt, für das Sie ein Array innerhalb einer anderen Schnittstelle erstellen möchten, geben Sie "interface ISelectOptions {name1: type; name2: type;}" und dann innerhalb Ihrer BIG-Schnittstelle den Schlüssel ein, dessen Array Sie sein möchten dieser Typ, keyZ: ISelectOptions []; wenn Sie dann den JSON erstellen, ist myVar: BIG = {key1: val1, key2: val2,…, keyZ: [{name1: valA, name2: valB}, {name1: valC, name2 : valD}] hat wie ein Champion funktioniert! (musste die Array-Klasse jedoch nicht erweitern) Danke!
— AppDreamer

4

Verwende nicht

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

Sie erhalten Fehler für alle Arrays-Eigenschaften und -Methoden wie Spleißen usw.

Die Lösung besteht darin, eine Schnittstelle zu erstellen, die ein Array einer anderen Schnittstelle definiert (die das Objekt definiert).

Beispielsweise:

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

3

Das können Sie auch.

            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

Einfache Option ohne tslint Fehler ...

export interface MyItem {
    id: number
    name: string
}

export type MyItemList = [MyItem]

4
Der exportierte MyItemListTyp ist "ein Ein-Element-Array von MyItem"
— NoNameProvided

5
Darf es sein export type MyItemList = MyItem[]? IMO die Kombination einer Schnittstelle und eines Typ-Alias ​​ist die beste Lösung für diesen Fall, da Sie alle Methoden des Array-Typs in Ihrem Typ-Alias ​​haben
— Pau Fracés

2

Hier ist eine Inline-Version, wenn Sie keinen neuen Typ erstellen möchten:

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

0

Die Programmierung ist einfach. Verwenden Sie einen einfachen Anwendungsfall:

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

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.