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'.
– TypeScript Playground
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
– TypeScript Playground
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.
– TypeScript Playground