使用上下文类型而不是从推理

时间:2017-04-21 12:38:04

标签: typescript

使用Typescript 2.2.2(strictNullChecks选项为true)我对以下内容感到惊讶。这是一个错误还是预期的行为?

interface Fn {
    (value: any): number;
}

var example1: Fn = function(value) {
    if (value === -1) {
        return undefined;  // no error, was expecting error
    }
    return value;
};

var example2 = function(value: any): number {
    if (value === -1) {
        return undefined;  // errors correctly
    }
    return value;
};

我理解example1没有错误,因为函数返回类型被推断为any | undefined。然后将any | undefinedFn返回类型的上下文类型进行比较,即number,从而发现它是兼容的。我反而期望函数的返回类型由上下文类型设置而不是与之比较。有没有办法强制执行另一个让Fn的使用者也明确键入函数返回的其他方法?

我想这会回到接口,只提供必须履行的合同,而不是指示包括返回类型在内的实现。

此外(感兴趣)当参数类型(number)导致推断的返回类型(number | undefined)与上下文类型(来自{{1})不兼容时,错误显然会被捕获},即Fn2):

number

2 个答案:

答案 0 :(得分:1)

对此的一个解决方案是用所有可用的基元和非基元替换any

interface Fn {
    (value: number | string | boolean | null | undefined | object): number;
}

// `example1` now errors as expected due to having a return type which is incompatible:
//     Type 'string | number | boolean | object | null | undefined' is not assignable to type 'number'.
//         Type 'undefined' is not assignable to type 'number'.
var example1: Fn = function(value) {
    if (value === -1) {
        return undefined;
    }
    return value;
};

For an excellent explanation of why this works please see FstTesla's answer.

答案 1 :(得分:1)

您分配给example1的函数表达式的确切推断类型为(value: any) => any,因为返回类型any | undefined已“折叠”为any。此类型与Fn兼容,因此被接受。

  

我想这会回到接口,只提供必须履行的合同,而不是指示包括返回类型在内的实现。

事实并非如此。相反,类型一致性非常严格 - 毕竟这是TypeScript的目的:) - 除了涉及any时,当然是语言中最宽松的类型。

上下文键入不会将对变量声明的类型应用于函数表达式。相反,return语句的类型有助于确定函数表达式的类型。出于这个原因,我认为在example1的表达式中没有显式类型注释的情况下,没有办法实现类型安全性。

请注意example1example3之间的区别在于any是特殊的,包含undefined,导致第一个中描述的“崩溃”行为段落。