118

I have a generic interface like this example with a single type constraint:

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

Is it possible to specify multiple type constraints instead of just one?

thorn0
  • 9,362
  • 3
  • 68
  • 96
Fenton
  • 241,084
  • 71
  • 387
  • 401

3 Answers3

148

Typescript doesn't offer a syntax to get multiple inheritance for generic types. However, you can achieve similar semantics by using the Union types and Intersection types. In your case, you want an intersection :

interface Example<T extends MyClass & OtherClass> {}

For a Union of both types :

interface Example<T extends MyClass | OtherClass> {}
José Cabo
  • 6,149
  • 3
  • 28
  • 39
STO
  • 10,390
  • 8
  • 32
  • 32
  • 6
    Union types are a great way to achieve this as you don't need to create an interface for the sole purpose of the constraint. They didn't exist back in 2013 - but this is definitely how I'd recommend doing it now. – Fenton Aug 11 '16 at 15:44
  • 11
    This answer is wrong. Union types don't have the same semantics as extending two distinct types at all. – AlexG Aug 30 '16 at 08:58
  • 4
    @AlexG Sure this is not the same as _extending_ two types but the same as _implementing_ two interfaces. – STO Nov 30 '16 at 11:28
  • 1
    You need to change this to `T extends MyClass | OtherClass` to make this work. As things stand, T is expected to be both MyClass and OtherClass -- a single constraint. – Joe Lapp Jan 31 '18 at 03:26
  • 7
    Also keep in mind that Typescript supports intersection types as well. So `` requires that the type implement both interfaces. – Tyler Cloutier Jul 09 '18 at 22:24
  • 2
    As far as I understand semantic of `extends A|B` is extends A OR B as `extends A & B` is extend both! so maybe you should specify both in your answer.... – Pipo Feb 08 '19 at 17:48
42

A work around for this would be to use a super-interface (which also answers the question "why would you allow an interface to inherit from a class").

interface ISuperInterface extends MyClass, OtherClass {

}

export interface IExample<T extends ISuperInterface> {
    getById(id: number): T;
}
Fenton
  • 241,084
  • 71
  • 387
  • 401
  • 15
    This is the right solution. Extending an interface from two classes is kind of scary, though -- if both declare private members, the interface is unfulfillable – Ryan Cavanaugh Jun 15 '13 at 17:41
1

Ref the comment about an interface deriving from a class...whats in a name?

I found this in section 3.5 of the 0.9.0 spec:

Interface declarations only introduce named types, whereas class declarations introduce named types and constructor functions that create instances of implementations of those named types. The named types introduced by class and interface declarations have only minor differences (classes can’t declare optional members and interfaces can’t declare private members) and are in most contexts interchangeable. In particular, class declarations with only public members introduce named types that function exactly like those created by interface declarations.

andyks
  • 478
  • 1
  • 5
  • 9