openapi-typescript
openapi-typescript copied to clipboard
The mock setup example can not infer response bodies with disjunct content-types
Description
The mock setup example given in the documentation pages does not infer the parameter type for mockResponses correctly when two different status codes in the schema return different content types.
In my case this happened when I had a 200 returning an "application/json" and a 400 returning an "application/problem+json".
From some fiddling around, the point where it breaks seems to be the keyof Obj in FilterKeys. Using keyof on a union of objects with non-overlapping keys returns never.
Reproduction
// type helpers — ignore these; these just make TS lookups better
type FilterKeys<Obj, Matchers> = {
[K in keyof Obj]: K extends Matchers ? Obj[K] : never;
}[keyof Obj];
type PathResponses<T> = T extends { responses: any } ? T["responses"] : unknown;
type OperationContent<T> = T extends { content: any } ? T["content"] : unknown;
type MediaType = `${string}/${string}`;
type MockedResponse<T, Status extends keyof T = keyof T> = FilterKeys<
OperationContent<T[Status]>,
MediaType
> extends never
? { status: Status; body?: never }
: {
status: Status;
body: FilterKeys<OperationContent<T[Status]>, MediaType>;
};
// additional repro stuff, not from the example
type Rs = {
200: {
content: {
"application/json": {
jwt?: string;
};
};
};
400: {
content: {
"application/problem+json": {
statusCode?: number;
message?: string;
errors?: {
[key: string]: string[];
};
};
};
};
403: {
content: never;
};
500: {
content: never;
};
};
type Oc = OperationContent<Rs[200 | 400]>;
type K = keyof Oc;
type Ks = FilterKeys<Oc, MediaType>;
type Mrs = MockedResponse<Rs, 200>;
type Mrs2 = MockedResponse<Rs, 400>;
type Mrs3 = MockedResponse<Rs>;
Observe:
Ocis a union of objects with non-overlapping keysKandKsisneverMrsandMrs2can resolve their respective bodiesMrs3can not
Expected result
The bodies should be resolved.
Checklist
- [X] I’m willing to open a PR (see CONTRIBUTING.md) (Provided I figure out a better way to overcome this obstacle than just adding a generic param to
mockResponsesand passing that toMockedResponsein its parameter.)