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

log*_*yth 7 typescript conditional-types

此示例不进行类型检查:

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);
}
Run Code Online (Sandbox Code Playgroud)

( TS 游乐场)

这个错误是因为extra被硬编码stringdoSubset1Thing,但在逻辑上它始终是一个字符串,因为value被限制Subset1,并Extra<Subset1>正确解析到string,但由于某些原因,调用doThing不承认。

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

对于第二个,如果Subset1Subset2重叠,我可以看到一些问题,但它们没有,所以我假设 TS 会将所有内容都归结为undefinedfor doSubset2Thing

有什么办法可以使这项工作?或者,我是否错过了实际上确实使此无效的内容?

kay*_*ya3 2

据我所知,在这种情况下,您的代码在逻辑上是正确且类型安全的,但 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 {
    // ...
}
Run Code Online (Sandbox Code Playgroud)

游乐场链接