Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/typescript/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
TypeScript编译器无法从联合类型参数中消除筛选的类型_Typescript - Fatal编程技术网

TypeScript编译器无法从联合类型参数中消除筛选的类型

TypeScript编译器无法从联合类型参数中消除筛选的类型,typescript,Typescript,我遇到了TypeScript编译器的问题,如果有人能提供帮助,我将不胜感激 我已经尽可能减少了问题的原始代码,我相信问题的根源来自第二个if语句 // This code generates a compile error. let val: boolean; function foo(bar: string | string[] | boolean, qux: string[]): void { if ('boolean' === typeof bar) { val

我遇到了TypeScript编译器的问题,如果有人能提供帮助,我将不胜感激

我已经尽可能减少了问题的原始代码,我相信问题的根源来自第二个
if
语句

// This code generates a compile error.

let val: boolean;

function foo(bar: string | string[] | boolean, qux: string[]): void {
    if ('boolean' === typeof bar) {
        val = bar;
        // At this point TypeScript correctly knows the type of bar is `boolean`
        return;
    }
    // At this point TypeScript correctly knows the type of bar is `string | string[]`

    if (!Array.isArray(bar)) {
        // Here the compiler understand that `bar` can only be a `string`

        bar = [bar];
        // This is where things start getting wonky.
        //
        // Here the compiler thinks `bar` is of type `string | string[] | boolean`
        // We have eliminated `boolean` already. We also know that `bar` is not an array because we are 
        // inside this `if` block.
    }
    // At this point TypeScript correctly knows the type of bar is `string[]`

    val = qux.every(q => bar.includes(q)); // Here the compiler fails.
    // semantic error TS2339: Property 'includes' does not exist on type 'false'.
}
有趣的是,通过简单地更改函数的结构,编译器再次感到高兴。在这个函数中,我们提前退出并返回一个值。类型检查是相同的,但是因为我们返回了值,所以编译器正确理解了类型

// This code compiles just fine.

function foo(bar: string | string[] | boolean, qux: string[]): boolean {
    if ('boolean' === typeof bar) {
        return bar;
    }
    if (!Array.isArray(bar)) {
        return qux.includes(bar);
    }
    return bar.every(b => qux.includes(b));
}

所以在所有这些之后,我的问题是为什么两者都是
bar=[bar]
val=qx.every(q=>bar.includes(q))有不同的(错误的)类型吗?

这有点让人困惑,因为从表面上看,Typescript在lambda中给
bar
一个较弱的类型是错误的,并且在这个特定的代码中没有不安全的行为

但是,在一般情况下,Typescript在lambda中为
bar
提供较弱的类型是正确的,即使
bar
在lambda中使用的同一行上有较强的类型。可通过以下代码演示此问题:

function demo(x: string | number) {
    if(typeof x === 'number') {
        x = 'now x is a string';
    }

    // type is string here, so no error
    x.includes('now');

    // type is string | number here, so this is an error
    let f: Function = () => x.includes('now');

    x = 23;

    // type is number here
    f();
}

此代码不是类型安全的,因为尽管在声明函数时,
x
确实具有type
string
,但在调用函数时,
x
实际上具有type
number
;因此,没有
包含
方法。因此,Typescript对代码的抱怨是正确的。但是这个代码的结构和你的一样;您在lambda中使用了一个变量,Typescript不知道稍后该变量具有不同类型时不会调用lambda,因此在lambda的范围内,该变量具有较弱的类型

理论上,Typescript可以被设计为知道数组的
every
方法立即调用lambda,然后丢弃它,因此在您的特定代码中,每次调用lambda时,变量肯定是字符串。然而,Typescript的类型系统功能不够强大,无法知道lambda将在什么情况下被调用,如果它被调用,那么它将变得相当复杂


第二个示例没有错误,因为lambda在lambda中调用
qux.includes
,而不是
bar.includes
。由于变量
qux
始终具有类型
string[]
,并且没有从较弱的类型缩小,因此这不会导致问题。

非常有趣!我唯一仍然不明白的是
bar=[bar]是怎么回事
@DanielMorell这只是它显示方式的一个怪癖;紧跟在
bar=[bar]之后
,变量
bar
的类型正确无误,如果将鼠标悬停在该行的
bar
上,它就不会在IntelliSense中显示。但是如果您在下一行写入
,它将显示为
字符串
。隐马尔可夫模型。。。我使用的是WebStorm,如果我在下一行输入
bar
,我会得到
string | string[]| boolean
。这一定是WebStorm的一个问题。我很惊讶两者之间存在差异,因为两者应该从同一个源(即Typescript实现)获取信息。我不使用WebStorm,所以我恐怕无法进一步调查。