typescript 如何在一对相关类型上编写泛型函数

jhdbpxl9  于 2022-11-26  发布在  TypeScript
关注(0)|答案(1)|浏览(118)

我想在MessageResponse子类型之间创建一些抽象关系,这样我就可以有一个通用函数,它将Message作为参数,并返回Response。然而,每当函数被MessageTypeA类型调用时,我希望响应类型为ResponseTypeA,并希望TypeScript以某种方式确保这种关系。考虑以下TypeScript代码来说明问题:

type MessageTypeA = { a: string };
type MessageTypeB = { b: number };
type MessageTypeC = [number, number];

type Message = MessageTypeA | MessageTypeB | MessageTypeC;

type ResponseTypeA = { a: boolean; aa: number };
type ResponseTypeB = "hello" | "bye";
type ResponseTypeC = number;

type Reponse = ResponseTypeA | ResponseTypeB | ResponseTypeC;

type Pair<M extends Message, R extends Reponse> = {
  message: M;
  response: R;
};

// I know this should be some type of Map/Record instead
type ValidPairsMap =
  | Pair<MessageTypeA, ResponseTypeA>
  | Pair<MessageTypeB, ResponseTypeB>
  | Pair<MessageTypeC, ResponseTypeC>;

// Something like this, I know syntax is wrong here:
function sendMessageReturnResponse<T extends ValidPair>(
  message: typeof T.message
): typeof T.response {
  throw "idk how to do this";
}

function main() {
  let mesA: MessageTypeA = { a: "msg" };
  let resA: ResponseTypeA = sendMessageReturnResponse(mesA);
  // error: return value of sendMessageReturnResponse cannot be inferred to be ResponseTypeA
}

我可以做些什么来实现上述目标?

nbnkbykc

nbnkbykc1#

我相信你正在寻找这样的东西:

type MessageTypeA = { a: string };
type MessageTypeB = { b: number };
type MessageTypeC = [number, number];

type Message = MessageTypeA | MessageTypeB | MessageTypeC;

type ResponseTypeA = { a: boolean; aa: number };
type ResponseTypeB = "hello" | "bye";
type ResponseTypeC = number;

type Reponse = ResponseTypeA | ResponseTypeB | ResponseTypeC;

type Pair<M extends Message, R extends Reponse> = {
    message: M;
    response: R;
};

type ValidPairsMap =
    | Pair<MessageTypeA, ResponseTypeA>
    | Pair<MessageTypeB, ResponseTypeB>
    | Pair<MessageTypeC, ResponseTypeC>;

// Something like this, I know syntax is wrong here:
function sendMessageReturnResponse<Msg extends Message>(
    message: Msg
): Extract<ValidPairsMap, Pair<Msg, any>>['response'] {
    return null as any
}

function main() {
    let mesA: MessageTypeA = { a: "msg" };
    let resA: ResponseTypeA = sendMessageReturnResponse(mesA); // ok

}

Playground
sendMessageReturnResponse中,仅推断Message就足够了,然后允许您在Extract的帮助下过滤联合类型
这条线Extract<ValidPairsMap, Pair<Msg, any>>表示:从ValidPairsMap的并集中获取消息为Msg的对

相关问题