Jak mogę zdefiniować interfejs dla tablicy obiektów za pomocą Typescript?


115

Mam następujący interfejs i kod. Myślałem, że definicje robię poprawnie, ale pojawia się błąd:

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

i:

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

Błąd:

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

Odpowiedzi:


101

Możesz zdefiniować interfejs z indeksatorem :

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

33
Nie jest to „interfejs dla tablicy obiektów z
— Maszynopisem

Tak, twój przykład definiowania interfejsu tylko dla określonych pozycji byłby bardziej przydatnym sposobem, aby to zrobić. Rzadko byłoby mieć tablicę elementów, ale nie chcieć wygodnie odwoływać się do pojedynczego elementu. Użycie prawdziwej tablicy uwidacznia również .length w interfejsie, który prawdopodobnie będzie używany dość często.
— Douglas

Jak zdefiniować klasę, aby zaimplementować ten interfejs?
— alexey

18
Problem z tym rozwiązaniem polega na tym, że nie jest to Arrayinterfejs, dlatego wszystkie Arraywłaściwości i metody takie jak lengthlub pushbędą brakować.
— Norman Breau,

217

Nie musisz używać indeksatora (ponieważ jest on nieco mniej bezpieczny). Masz dwie możliwości:

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

Osobiście polecam opcję A (prostsza migracja, gdy używasz klas, a nie interfejsów).


3
Dodaje ?do wszystkich deklaracji w interfejsie np. id?: number; label?: string; key?: anynajlepszy sposób na uniknięcie problemu z rzutowaniem, jeśli używasz mniej właściwości niż to, co jest zdefiniowane w interfejsie? To znaczy. Nie mogę tego określić keyw konfiguracji wpisanej tablicy.
— GONeale

Opcja B jest przydatna, ponieważ umożliwia korzystanie z interfejsu podczas tworzenia interfejsów wyższego poziomu.
— aashtonk

1
Jezu Chryste, męczyło mnie to tak cholernie długo, dziękuję!
— Matthew Harwood,

2
Druga deklaracja interfejsu powoduje następujący błąd tslint: " interfejs deklarujący brak elementów członkowskich jest równoważny z jego nadtypem "
— Inigo

2
Mogę zasugerować, że „klucz” jest typu string | string [] zamiast dowolnego. W ten sposób: interface EnumServiceItem { id: number; label: string; key: string | string[] }
— JulianG

75

Możesz zdefiniować interfejs jako tablicę, po prostu rozszerzając interfejs Array.

export interface MyInterface extends Array<MyType> { }

Dzięki temu każdy obiekt, który implementuje, MyInterfacebędzie musiał zaimplementować wszystkie wywołania funkcji tablic i będzie mógł przechowywać tylko obiekty tego MyTypetypu.


6
Piękne rozwiązanie. To powinna być akceptowana odpowiedź.
— demisx

2
Dlaczego nie użyć type ( type MyTypeArray = Array<MyType>) zamiast rozszerzać interfejs?
— Pau Fracés

OP poprosił o interfejs, zakładam, że jest rozszerzony o inne właściwości i metody, nie można tego zrobić z typem, a także typ jest bardziej ograniczony niż interfejsy pod względem ogólnej użyteczności
— NoNameProvided

Typ @NoNameProvided "jest bardziej ograniczony niż interfejsy pod względem ogólnej użyteczności" Czy możesz podać więcej szczegółów na temat tego oświadczenia? Jakie są ograniczenia używania typów w porównaniu z interfejsami?
— Pau Fracés

1
Najlepszym rozwiązaniem niż inne powinno być akceptowana odpowiedź
— Andres Felipe

16

Dodatkowa łatwa opcja:

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

    type simpleType = simpleInt[];

6

Nie używać

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

Otrzymasz błędy dla wszystkich właściwości i metod Arrays, takich jak łączenie itp.

Rozwiązaniem jest stworzenie interfejsu, który definiuje tablicę innego interfejsu (który będzie definiował obiekt)

Na przykład:

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

4

W Angular użyj „extends”, aby zdefiniować interfejs dla „Array” obiektów.

Użycie indeksatora spowoduje błąd, ponieważ nie jest to interfejs typu Array, więc nie zawiera właściwości i metod.

na przykład

błąd TS2339: Właściwość „find” nie istnieje w typie „ISelectOptions2”.

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

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

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

Ta metoda spowoduje, że „Interfejs deklarujący brak elementów jest równoważny jego nadtypowi”, jeśli linter nie zezwala na puste interfejsy.
— demisx

Ta odpowiedź była bardzo bliska, pomogła mi rozwiązać mój problem! Dla początkowego obiektu, dla którego chcesz utworzyć tablicę w innym interfejsie, wpisz "interface ISelectOptions {nazwa1: typ; nazwa2: typ;}, a następnie w interfejsie BIG, gdy dojdziesz do klucza, który ma być tablicą ten typ, keyZ: ISelectOptions []; następnie podczas tworzenia JSON, myVar: BIG = {key1: val1, key2: val2,…, keyZ: [{name1: valA, name2: valB}, {name1: valC, name2 : valD}] działał jak mistrz! (nie trzeba było jednak rozszerzać klasy Array) Dzięki!
— AppDreamer

3

Ty też możesz to zrobić.

            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

Łatwa opcja bez błędów tslint ...

export interface MyItem {
    id: number
    name: string
}

export type MyItemList = [MyItem]

5
Wyeksportowanym MyItemListtypem będzie „jednoelementowa tablica MyItem”
— NoNameProvided

5
Może to być export type MyItemList = MyItem[]? IMO Połączenie interfejsu i aliasu typu jest najlepsze w tym przypadku, ponieważ w aliasie typu masz wszystkie metody typu Array
— Pau Fracés

2

Oto wersja wbudowana, jeśli nie chcesz tworzyć zupełnie nowego typu:

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

0

Programowanie jest proste. Użyj prostego przypadku:

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

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.