首页 > 解决方案 > 基于可区分联合的缩小打字稿泛型类型

问题描述

我有一些类型定义,如下所示。

type PayloadType = 'A' | 'B';

interface Payload<T extends PayloadType> {
  type: T;
}

interface PayloadA extends Payload<'A'> {
  state: string
}

interface PayloadB extends Payload<'B'> {
  serialNumber: string;
}

type TPayload = PayloadA | PayloadB;


type PayloadInterpretation<T extends TPayload> = {
  payload: T;
  entries: T[]; // This property is only for demonstration purpose
};

type TPayloadInterpretation = PayloadInterpretation<PayloadA> | PayloadInterpretation<PayloadB>;

function f(interpretation: TPayloadInterpretation) {
  if (interpretation.payload.type === 'B') {
    const payload = interpretation.payload; // payload is of type PayloadB
    const entries = interpretation.entries; // entries is of type PayloadA[] | PayloadB[]
  }
}

评论表明,即使是有效载荷的类型也可以正确地缩小到PayloadB基于区分联合,但类型仍然T[]是.entriesPayloadA[] | PayloadB[]

我在想如果 typescript 知道T有效载荷的类型PayloadA,它也应该能够缩小entries: T[]entries: PayloadB[]. 我知道我可以进行类型转换,例如:

function f(interpretation: TPayloadInterpretation) {
  if (interpretation.payload.type === 'B') {
    const payloadBInterpretation = interpretation as PayloadInterpretation<PayloadB>;
    ...
  }
}

但我的问题是有没有其他方法可以做到这一点?

代码打字稿操场上。

谢谢!

标签: javascripttypescripttypescript-generics

解决方案


当您检查 时interpretation.payload.type,您只是在缩小interpretation.payload对象。你实际上并没有做任何事情来缩小interpretation.entries.

换句话说,typescript 不知道interpretation.entries你也可以窄化interpretation.payload

如果您希望它们都被缩小,您需要在PayloadInterpretation类型中添加另一个鉴别器:

// ...

type PayloadInterpretation<T extends TPayload> = {
  type: T['type']; // the new discriminator for the whole PayloadInterpretation
  payload: T;
  entries: T[];
};

// ...

function f(interpretation: TPayloadInterpretation) {
  if (interpretation.type === 'B') { // narrowing the whole interpretation instead of only interpretation.payload
    const payload = interpretation.payload; // payload is of type PayloadB
    const entries = interpretation.entries; // entries is of type PayloadB[]
  }
}

推荐阅读