我在下面彻底评论了代码。我觉得像这样理解问题要容易得多,而不是试图仅仅通过世界来解释它。
abstract class BaseEvent<REQUEST_PAYLOAD, RESPONSE_PAYLOAD> {
constructor(public requestPayload: REQUEST_PAYLOAD) {}
// this method was only created for the sake of showing response1 type example
public return_RESPONSE_PAYLOAD_type(): RESPONSE_PAYLOAD {
return null;
}
}
type GetUserInfoRequest = { userId: number };
type GetUserInfoResponse = { username: string; age: number };
class GetUserInfoEvent extends BaseEvent<
GetUserInfoRequest,
GetUserInfoResponse
> {}
const emit = async <
REQUEST_PAYLOAD,
RESPONSE_PAYLOAD,
EVENT extends BaseEvent<REQUEST_PAYLOAD, RESPONSE_PAYLOAD>
>(
event: EVENT
): Promise<RESPONSE_PAYLOAD> => {
// some stuff will be done there - for the sake of example it was removed
return null;
// return event.return_RESPONSE_PAYLOAD_type(); // doesn't work aswell
};
const main = async () => {
const event = new GetUserInfoEvent({ userId: 666 });
const response1 = event.return_RESPONSE_PAYLOAD_type(); // type === { username: string; age: number; }
const response2 = await emit(event); // type === {} but I want it to be { username: string; age: number; }
// response2.username <-- error
// response2.age <-- error
// I want emit function to return current RESPONSE_PAYLOAD type instead of an empty object. I don't want to manually cast returned types to GetUserInfoResponse because I want to achieve 100% type safety.
};
main();
我可能不应该对它进行过typescript@3.2.4
的测试。
答案 0 :(得分:2)
使用可以使用条件类型从EVENT
中提取type参数。通常不会基于一个类型参数来推断类型参数,并且最终会得到最窄的类型(在这种情况下为{}
)
abstract class BaseEvent<REQUEST_PAYLOAD, RESPONSE_PAYLOAD> {
constructor(public requestPayload: REQUEST_PAYLOAD) { }
// this method was only created for the sake of showing response1 type example
public return_RESPONSE_PAYLOAD_type(): RESPONSE_PAYLOAD {
return null;
}
}
type GetUserInfoRequest = { userId: number };
type GetUserInfoResponse = { username: string; age: number };
class GetUserInfoEvent extends BaseEvent<
GetUserInfoRequest,
GetUserInfoResponse
> { }
// Conditional type to extract the response payload type:
type RESPONSE_PAYLOAD<T extends BaseEvent<any, any>> = T extends BaseEvent<any, infer U> ? U : never;
const emit = async <
EVENT extends BaseEvent<any, any>
>(
event: EVENT
): Promise<RESPONSE_PAYLOAD<EVENT>> => {
// some stuff will be done there - for the sake of example it was removed
return null;
// return event.return_RESPONSE_PAYLOAD_type(); // doesn't work aswell
};
const main = async () => {
const event = new GetUserInfoEvent({ userId: 666 });
const response1 = event.return_RESPONSE_PAYLOAD_type(); // type === { username: string; age: number; }
const response2 = await emit(event); // is now GetUserInfoResponse
response2.username //<-- ok
response2.age //<-- ok
};