Czy można określić wiele ograniczeń typu dla typów ogólnych TypeScript

83

Mam ogólny interfejs, taki jak ten przykład z jednym ograniczeniem typu:

export interface IExample<T extends MyClass> {
    getById(id: number): T;
}

Czy można określić wiele ograniczeń typu zamiast tylko jednego?

Fenton
źródło

Odpowiedzi:

87

Typescript nie oferuje składni umożliwiającej wielokrotne dziedziczenie dla typów ogólnych. Możesz jednak osiągnąć podobną semantykę, używając typów Union i Intersection. W twoim przypadku chcesz skrzyżowania:

interface Example<T extends MyClass & OtherClass> {}

Dla związku obu typów:

interface Example<T extends MyClass | OtherClass> {}
STO
źródło
4
Typy unii to świetny sposób na osiągnięcie tego, ponieważ nie trzeba tworzyć interfejsu wyłącznie w celu ograniczenia. Nie istniały jeszcze w 2013 roku - ale zdecydowanie polecam to teraz.
Fenton,
5
Ta odpowiedź jest błędna. Typy unii nie mają takiej samej semantyki, jak w ogóle rozszerzenie dwóch różnych typów.
AlexG,
3
@AlexG Jasne, że to nie to samo, co rozszerzenie dwóch typów, ale to samo, co implementacja dwóch interfejsów.
STO
6
Należy również pamiętać, że Typescript obsługuje również typy przecięć. Dlatego <T extends MyInterfaceA & MyInterfaceB>wymaga, aby typ implementował oba interfejsy.
Tyler Cloutier
2
O ile rozumiem, semantyka extends A|Brozciąga się na A LUB B, a także na extends A & Boba! więc może powinieneś określić oba w swojej odpowiedzi ...
Pipo,
34

Rozwiązaniem tego problemu byłoby użycie superinterfejsu (który również odpowiada na pytanie „dlaczego miałbyś pozwolić interfejsowi na dziedziczenie z klasy”).

interface ISuperInterface extends MyClass, OtherClass {

}

export interface IExample<T extends ISuperInterface> {
    getById(id: number): T;
}
Fenton
źródło
12
To jest właściwe rozwiązanie. Rozszerzenie interfejsu z dwóch klas jest jednak trochę przerażające - jeśli obie deklarują członków prywatnych, interfejs jest niewykonalny
Ryan Cavanaugh
1

Odwołaj się do komentarza o interfejsie pochodzącym z klasy ... co jest w nazwie?

Znalazłem to w sekcji 3.5 specyfikacji 0.9.0:

Deklaracje interfejsów wprowadzają tylko nazwane typy, podczas gdy deklaracje klas wprowadzają nazwane typy i funkcje konstruktora, które tworzą wystąpienia implementacji tych nazwanych typów. Nazwane typy wprowadzone przez deklaracje klas i interfejsów mają tylko niewielkie różnice (klasy nie mogą deklarować opcjonalnych elementów członkowskich, a interfejsy nie mogą deklarować prywatnych elementów członkowskich) i są w większości kontekstów wymienne. W szczególności deklaracje klas zawierające tylko publiczne elementy członkowskie wprowadzają nazwane typy, które działają dokładnie tak samo, jak te utworzone przez deklaracje interfejsu.

andyks
źródło
Opcjonalni członkowie klasy są teraz zaimplementowani: github.com/Microsoft/TypeScript/pull/8625
Stefan Rein