以无缝方式使用打字稿联合

Use typescript unions in a seamless way

我说的后端有一个 API 来创建订单。 这样的订单是有商品的,客户端收到的时候只是ID指定,服务器发送的时候是完整的明细对象。

打字稿界面应该是这样的:

export interface Order {
  userId: number;
  bought_products: BoughtProduct[];
}

export interface BoughtProduct {
  quantity: number;
  product: number | Product; // not specified here
  created?: string; // other keys are optional because only present if sent by Backend
}

如果 typescript 解释器能够理解我何时将产品用作数字或接收产品作为对象,而无需显式强制转换,那将是完美的。
这是因为,因为它是一个嵌套数组,所以使用强制转换会很复杂。

可以在 this playground link

中看到一个更直接的问题示例

Typescript 足够聪明,如果您之前输入检查过它,它会自动为您转换它,例如

if (typeof boughtProduct.product === "number" {
     // it will be handled as number
} else {
     // it will be handled as Product
}

我会做这样的事情:

interface Order {
    userId: number;
    bought_products: Array<ClientBoughtProduct | ServerBoughtProduct>;
}

interface BoughtProduct<T> {
    quantity: number;
    product: T;
}

interface ClientBoughtProduct extends BoughtProduct<number> {}

interface ServerBoughtProduct extends BoughtProduct<Product> {
    created: string;
}

然后我会使用 user defined type guards:

function isClientBoughtProduct(obj: BoughtProduct<any>): obj is ClientBoughtProduct {
    return typeof obj.product === "number";
}

function isServerBoughtProduct(obj: BoughtProduct<any>): obj is ServerBoughtProduct {
    return typeof obj.product === "object";
}

if (isServerBoughtProduct(obj)) {
    // obj.created is available
}