Czy istnieje sposób na „wyodrębnienie” typu właściwości interfejsu TypeScript?

124

Załóżmy, że istnieje plik do pisania dla biblioteki X, który zawiera kilka interfejsów.

interface I1 {
    x: any;
}

interface I2 {
    y: {
        a: I1,
        b: I1,
        c: I1
    }
    z: any
}

Aby pracować z tą biblioteką, potrzebuję przekazać obiekt, który jest dokładnie tego samego typu co I2.y. Mogę oczywiście stworzyć identyczny interfejs w moich plikach źródłowych:

interface MyInterface {
    a: I1,
    b: I1,
    c: I1
}

let myVar: MyInterface;

ale potem spoczywa na mnie ciężar utrzymywania go na bieżąco z tym z biblioteki, ponadto może być bardzo duży i powodować duplikowanie kodu.

Czy zatem istnieje sposób na „wyodrębnienie” typu tej konkretnej właściwości interfejsu? Coś podobnego do let myVar: typeof I2.y(co nie działa i powoduje błąd „Nie można znaleźć nazwy I2”). Z góry dziękuję.


Edycja : po zabawie trochę w TS Playground zauważyłem, że następujący kod osiąga dokładnie to, co chcę:

declare var x: I2;
let y: typeof x.y;

Jednak wymaga xzadeklarowania zbędnej zmiennej . Szukam sposobu, aby to osiągnąć bez tej deklaracji.

Kuba Jagoda
źródło
1
co nie działa - jak to się objawia? Jaki jest rzeczywisty komunikat o błędzie, który widzisz?
Bartek Banachewicz
@BartekBanachewicz zaktualizowane
Kuba Jagoda

Odpowiedzi:

250

Wcześniej nie było to możliwe, ale na szczęście jest teraz, ponieważ TypeScript w wersji 2.1 . Został wydany 7 grudnia 2016 roku i wprowadza indeksowane typy dostępu, zwane również typami wyszukiwania .

Składnia wygląda dokładnie jak dostęp do elementu, ale jest zapisana w miejsce typów. Więc w twoim przypadku:

interface I1 {
    x: any;
}

interface I2 {
    y: {
        a: I1,
        b: I1,
        c: I1
    }
    z: any
}

let myVar: I2['y'];  // indexed access type

Teraz myVarma typ I2.y.

Sprawdź to w TypeScript Playground .

Michał Miszczyszyn
źródło
1
W przypadku, gdy „y” jest tablicą, czy istnieje sposób na wyodrębnienie typu elementów? np. I2 {y: {..} []}
Jan B
1
@JohnB tak, możesz to zrobić dokładnie w ten sam sposób, ponieważ indeksy tablic są jak właściwości obiektów. Sprawdź to tutaj: typescriptlang.org/play/…
Kuba Jagoda
3
@JohnB tak, możesz uzyskać do niego dostęp w ten sam sposób, tj. I2['y'][0]Zobacz: typescriptlang.org/play/...
Michał Miszczyszyn
2
To naprawdę niesamowita umiejętność
Geradlus_RU
1
Załóżmy, że przeglądamy klucze obiektu zdefiniowanego przy użyciu I2typu. Jak uzyskać typ określonego klucza dynamicznie podczas wykonywania pętli. To; let z: typeof x[a];, gdzie ajest określony klucz jako ciąg, nie działa. Mówi mi, że aodnosi się do wartości i musi odnosić się do typu. Jak bym to zrobił? Czy jest to w ogóle możliwe? Dzięki!
Emil Walser
-2

Interfejs jest jak definicja obiektu. Wtedy y jest własnością twojego obiektu I2, czyli jest pewnego typu, w tym przypadku "anonimowy".

Możesz użyć innego interfejsu do zdefiniowania y, a następnie użyć go jako swojego typu y w ten sposób

interface ytype {
   a: I1;
   b: I1;
   c: I1;
}

interface I2 {
    y: ytype;
    z: any;
}

Możesz umieścić swój interfejs w pliku i użyć ekstraktu, aby móc zaimportować go do innych plików swoich projektów

export interface ytype {
   a: I1;
   b: I1;
   c: I1;
}



 export interface I2 {
        y: ytype;
        z: any;
    }

Możesz to zaimportować w ten sposób:

   import {I1, I2, ytype} from 'your_file'
JCorriveau
źródło
Wszystko w porządku, ale jak już wspomniałem - interfejsy I1 i I2 pochodzą z zewnętrznej biblioteki i są zdefiniowane w pliku d.ts dla tej biblioteki. Dlatego posiadanie tego interfejsu ytype byłoby powieleniem kodu i wymagałoby ciągłej aktualizacji.
Kuba Jagoda