Reputation: 843
Here is my interface:
interface Responses {
200:{
foo:number;
};
204:{
bar:number;
};
}
I can get any of the property type as follow:
type TypeFor200 = Responses['200'];
However I would like to make it conditional so that if 200
property is not exist in the interface, it should return the type for 204
, something like this:
type AnyType= Responses extends 200 ? Responses['200'] : Responses['204'] ;
If both 200
and 204
exist, the above example will work, otherwise will throw an error complaining that the property does not exist.
Note that I cannot make a change to Responses
interface since it is in an autogenerated file.
How should I go about doing this?
Upvotes: 1
Views: 1367
Reputation: 9701
The conditional type you're going for seems to be a red flag for me. I can't think of a construct where this would be useful or necessary. TypeScript already errors when you try to access a property that does not exist on an interface.
interface Responses {
200: {
foo: number
}
}
type NoContentResponse = Responses['204'];
^^^^^
Property '204' does not exist on type 'Responses'.
So you should just annotate the types correctly or break down your types so that you can use each fragment and compose them as necessary as opposed to use a conditional type like what you're trying to go for. However I can't think of everything so maybe you really have a use case for a conditional type.
The conditional you want is <key> extends keyof <interface>
. This checks for the existence of a key. It would have to be constructed into a generic type. Something like this:
type Foo<A, B, C> = B extends keyof A ? A[B] :
C extends keyof A ? A[C] :
undefined;
An example with the resultant types is below:
interface OkResponse {
200:{
foo:number;
};
}
interface NoContentResponse {
204:{
bar:number;
};
}
interface NotAResponse {}
type OkAndNoContent = OkResponse & NoContentResponse;
type NoContent = NoContentResponse;
type Foo<A, B, C> = B extends keyof A ? A[B] :
C extends keyof A ? A[C] :
undefined;
type TypeForOk = Foo<OkAndNoContent, 200, 204>; // { foo: number; }
type TypeForNoContent = Foo<NoContent, 200, 204>; // { bar: number; }
type TypeForNotAResponse = Foo<NotAResponse, 200, 204> // undefined
You can't do extends keyof
outside of a generic type because TypeScript has enough type information to give you an error, another reason why this seems to be a red flag for me:
interface NoContentResponse {
204:{
bar:number;
};
}
type TypeForNoContent = '200' extends keyof NoContentResponse ?
NoContentResponse['200'] : NoContentResponse['204'];
^^^^^
Type '"200"' cannot be used as an index type.
Upvotes: 2