处理受歧视的联合,其中鉴别器是联合类型

问题描述 投票:0回答:1

我正在努力缩小一个复杂的受歧视联盟的范围。

我使用了一堆

if
并提前返回来消除所有情况,但最后,我发现自己有 2 个默认类型位于鉴别器上,是联合类型,并且缩小停止工作。

我有一个简单的片段来演示我的问题。

interface Foo {
  foo: string;
  type: 'foo';
}

interface BarBaz {
  bar: string;
  type: 'bar' | 'baz';
}

const func = function (arg: Foo | BarBaz) {
  if (arg.type === 'bar' || arg.type === 'baz') {
    return 'whatever';
  }

  arg; // type Foo or BarBaz expecting Foo
};

我想,我应该只有唯一的鉴别器,但是有没有一种简单的方法可以摆脱这个死胡同?

typescript typescript2.0 discriminated-union discriminator
1个回答
0
投票

这被认为是 TypeScript 的设计限制,报告于 microsoft/TypeScript#31404。虽然检查的真实分支按预期缩小,但 TypeScript 缺乏在错误分支中执行任何有用操作所需的反事实分析。

如果你需要这个工作,你就必须解决它。一种方法是创建一个自定义类型保护函数来显式区分联合:

function discrimUnion<
  T extends Record<K, any>, 
  K extends PropertyKey, 
  const V extends T[K]
>(t: T, k: K, ...v: V[]): t is Extract<T, Record<K, V>> {
    return v.includes(t[k]);
}

const func = function (arg: Foo | BarBaz) {
    if (discrimUnion(arg, "type", "bar", "baz")) {
        arg // BarBaz
        return 'whatever';
    }
    arg; // Foo
    return;
};

或者您可以更改为

switch
/
case
语句,这似乎更能确定详尽性:

const func = function (arg: Foo | BarBaz) {
    switch (arg.type) {
        case "bar":
        case "baz": {
            arg; // BarBaz
            return 'whatever'
        }
        default: {
            arg // Foo
            return;
        }
    }
}

Playground 代码链接

© www.soinside.com 2019 - 2024. All rights reserved.