I'm writing a function whose job it is to take a raw api response and transform it into a shape that is more easily consumable in my app (let's call it a "pretty" response).
The code below is valid according to the TS compiler, but I want it to complain that I haven't removed the metadata key from the raw response before returning, as metadata exists in RawResponse but not in PrettyResponse.
I thought that my Optionalize type would do this for me, but it doesn't seem to be working.
What am I misunderstanding here?
Here's a TS Playground link to illustrate as well.
// Omit from T the keys in common with K
type Optionalize<T extends K, K> = Omit<T, keyof K>;
interface RawResponse {
data: [];
metadata: Object;
}
type PrettyResponse<T extends RawResponse> = Optionalize<T, RawResponse> & {
data: [];
version: string;
};
/**
* Take a raw api response and transform it into a pretty one.
* All raw responses have at least the keys of RawResponse.
*/
function parseResponse<T extends RawResponse>(response: T): PrettyResponse<T> {
const result = Object.assign({}, response, {
version: '123'
});
// Shouldn't I have to delete result.metadata before returning?
return result;
}
And an example of consuming it:
interface MyResponse {
data: [];
name: string;
category: string;
other?: number;
metadata: Object;
}
const response: MyResponse = {
data: [],
name: 'a',
category: 'blah',
metadata: {}
}
const myPrettyResponse: PrettyResponse<MyResponse> = parseResponse<MyResponse>(response);
Note: My colleague pointed out that this may be due to Typescript's use of structural subtyping, but I would still expect the explicit return definition of Optionalize<T, RawResponse> to remove the metadata key.