Можно ли вернуть универсальный тип из аргумента, переданного функции
Я подробно прокомментировал код ниже. Я чувствую, что гораздо проще понять эту проблему, чем пытаться объяснить ее только с помощью миров.
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
,
1 ответ
Решение
Использование может использовать условный тип для извлечения аргумента типа из EVENT
, Параметры типа обычно не выводятся один на основе другого, и в итоге вы получаете самый узкий тип (в данном случае {}
)
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
};