I have a method that makes a request to a server and, based on the URL, it might return completely differently shaped data.
Before this I was just casting the expected interface into the returned object:
const data = Promise.resolve(makeSignedRequest(requestParameters));
return data as Promise<AwesomeResponse>;
but today I came across this syntax, where I can tell the method explicitly what kind of data I'm expecting:
const data = Promise.resolve(makeSignedRequest<AwesomeResponse>(requestParameters));
return data;
Now. the makeSignedRequest may return types like, AwesomeResponse
, GreatResponse
, AmazingResponse
but there is a common thing in all these. They all share the same structure - the structure of BaseResponse
.
All my responses extend the BaseResponse
, so we're cool there.
Having said all that, TypeScript is still complaining about the following code:
import https from "https";
export interface BaseResponse {
meta: {};
data: Array<{}>;
error?: {
statusCode: number | undefined;
statusMessage: string | undefined;
};
}
export const makeSignedRequest = <T>(url): Promise<T> => {
return new Promise((resolve, reject) => {
// create Request with event listeners
const req = https.request(url, (res) => {
res.on("end", () => {
if (res.statusCode !== 200) {
resolve({
data: [],
meta: {},
error: {}
});
}
});
});
});
};
the resolve({data: [],
gets heavily underlined by VS Code, because as I mentioned in the title,
Argument of type '{ data: never[]; meta: {}; error: { statusCode: number | undefined; statusMessage: string | undefined; }; }' is not assignable to parameter of type 'T | PromiseLike<T> | undefined'.
Object literal may only specify known properties, and 'data' does not exist in type 'PromiseLike<T>'.
What am I missing here?
You need a generic constraint :
export const makeSignedRequest = < T extends BaseResponse > ...
and a type assertion:
resolve({
data: [],
meta: {},
error: {
statusCode: res.statusCode,
statusMessage: res.statusMessage,
},
} as T);
This code works for me in VSCode with TS 3.8.3
export interface BaseResponse {
data: [];
meta: {};
error?: {
statusCode: number | undefined;
statusMessage: string | undefined;
};
}
function makeSignedRequest<T extends BaseResponse>(): Promise<T> {
return new Promise((resolve, reject) => {
// create Request with event listener
resolve({
data: [],
meta: {},
error: {},
} as T);
});
}
You are saying that: your function return a generic type Promise, so resolve
only accepts T as parameter. But {data: [], meta: {}, error: {}}
is not T, as T can be anything (string, number...), so it won't compile. Your function does not make sense with generic type, it should return Promise<BaseReponse>
, that's all. Return Promise<T>
does not produce any benefit
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.