条件类型无法识别所有输入都会产生相同的条件结果

Conditional type doesn't recognize that all inputs result in same conditional result

这个例子没有类型检查:

type Subset1 = "one" | "two";
type Subset2 = "three" | "four";
type All = Subset1 | Subset2;

type Other = {
    "one": number,
    "two": string,
    "three": boolean,
    "four": object,
};

type Extra<V> = V extends Subset1 ? string : undefined;

function doOtherThing(stuff: string){}

function doThing<V extends All>(value: V, params: Other[V], extra: Extra<V>) { }

function doSubset1Thing<V extends Subset1>(value: V, params: Other[V], extra: string) {
    doThing(value, params, extra);

    doOtherThing(extra);
}

function doSubset2Thing<V extends Subset2>(value: V, params: Other[V]) {
    doThing(value, params, undefined);
}

(TS Playground)

错误是因为 extradoSubset1Thing 中被硬编码 string,但逻辑上它 总是一个字符串,因为 value 仅限于 Subset1Extra<Subset1> 正确解析为 string,但出于某种原因,对 doThing 的调用无法识别。

同样,即使第三个参数始终为 undefined.

,也会为 doSubset2Thing 错误反转它

对于第二个,如果 Subset1Subset2 重叠,我可以看到一些问题,但它们没有重叠,所以我假设 TS 会把这一切都弄平undefined 对于 doSubset2Thing

有什么方法可以让它工作吗?或者,我是否遗漏了一些实际上使它无效的东西?

据我所知,这是一个您的代码在逻辑上正确且类型安全的实例,但 Typescript 无法证明这一点,因为它缺少能够证明这一点的规则。像 "V 这样的简单规则必须扩展 Subset1 因为这是它的上限" 就足够了,但显然 Typescript 没有(当前)被编程为使用这样的规定。

一个修复方法可能比条件类型对您的用例更有意义,它是使用函数重载:这也使您不必在第二种情况下传递显式 undefined

function doThing<V extends Subset1>(value: V, params: Other[V], extra: string): void;
function doThing<V extends Subset2>(value: V, params: Other[V]): void;
function doThing<V extends All>(value: V, params: Other[V], extra?: string): void {
    // ...
}

Playground Link