在不使用if或switch的情况下键入可区分的联合的类型

时间:2018-12-28 00:09:39

标签: typescript

我想用一个对象上的一个键来缩小字体。示例:

class TextNode {
  readonly type = 'text_node';
}

class ImageNode {
  readonly type = 'image_node';
  url: string;
}

type MarkupNode = TextNode | ImageNode;

type Hook<Type extends MarkupNode['type']> = (node: { type: Type }) => { type: Type };

type Hooks = { [NodeType in MarkupNode['type']]?: Hook<NodeType> };

const hooks: Hooks = {
  image_node: node => { // I'd like node to be an ImageNode
    node.url = 'https://images.com/the-image';
    return node;
  },
};

这当然会导致错误Property 'url' does not exist on type '{ type: "text_node"; }'。令人反感的行是type Hook<Type> = (node: { type: Type }) => { type: Type };,但我不确定是否可以在此处提取正确的MarkupNode类型。

也许我需要一个辅助函数来包装hooks对象?

1 个答案:

答案 0 :(得分:1)

您可以执行所需的操作,但是在映射类型中,您将需要使用Extract条件类型来提取联合的适当成员:

class TextNode {
    readonly type = 'text_node';
}

class ImageNode {
    readonly type = 'image_node';
    url: string;
}

type MarkupNode = TextNode | ImageNode;

type Hook<TNode> = (node: TNode) => TNode;

type Hooks = { [NodeType in MarkupNode['type']]?: Hook<Extract<MarkupNode, { type: NodeType }>> };

const hooks: Hooks = {
    image_node: node => { // is now ImageNode
        node.url = 'https://images.com/the-image';
        return node;
    },
};

Extract条件类型将提取与第二个type参数中指定的type相同的type的并集类型。