【问题标题】:Typescript: Overloads with optional parameters not working when strictNullChecks is enabled打字稿:启用 strictNullChecks 时,带有可选参数的重载不起作用
【发布时间】:2019-11-06 11:46:40
【问题描述】:

我使用泛型和重载的组合来键入一个类,但是当启用strictNullChecks 时,我的重载中的可选参数出现问题。我怎样才能让它在启用strictNullChecks 的情况下工作?

一个简单的示例测试用例失败,并显示“'T | undefined' 类型的参数不可分配给 'undefined' 类型的参数。”仅当启用strictNullChecks 时:

class BaseClass { }
class BaseClass2 { }

class Test<T extends BaseClass, R extends BaseClass2> {
    test(a: T): R;
    test(a?: undefined): undefined;
    test(a?: any) {
        return a;
    }

    test2(b?: T) {
        // Errors only when strictNullChecks is enabled (can be switched on in the options tab above)
        return this.test(b) 
    }
}

const testClass = new Test<BaseClass, BaseClass2>()

// desired ouput
const output1: undefined = testClass.test2()
const output2: BaseClass2 = testClass.test2(new BaseClass())

或者在打字稿游乐场:https://www.typescriptlang.org/play/index.html#src=class%20BaseClass%20%7B%7D%0D%0A%0D%0Aclass%20BaseClass2%20%7B%20%7D%0D%0A%0D%0Aclass%20Test%3CT%20extends%20BaseClass%2C%20R%20extends%20BaseClass2%3E%20%7B%0D%0A%20%20%20%20testM(a%3A%20T%20%7C%20undefined%2C%20b%3A%20R)%20%7B%0D%0A%20%20%20%20%20%20%20%20if%20(a)%20%7B%0D%0A%20%20%20%20%20%20%20%20%20%20%20%20return%3B%0D%0A%20%20%20%20%20%20%20%20%7D%0D%0A%20%20%20%20%20%20%20%20return%20b%3B%0D%0A%20%20%20%20%7D%0D%0A%0D%0A%20%20%20%20testM2(d%3A%20R%2C%20c%3F%3A%20T)%20%7B%0D%0A%20%20%20%20%20%20%20%20return%20this.testM(c%2C%20d)%20%0D%0A%20%20%20%20%7D%0D%0A%7D%0D%0A%0D%0Aconst%20test%20%3D%20new%20Test%3CBaseClass%2C%20BaseClass2%3E()%0D%0A%0D%0Aconst%20output1%3A%20undefined%20%3D%20test.testM2(new%20BaseClass2()%2C%20undefined)%0D%0Aconst%20output2%3A%20BaseClass2%20%3D%20test.testM2(new%20BaseClass2()%2C%20new%20BaseClass())

编辑(2019 年 6 月 25 日 14:20):更新代码 sn-p 以反映所需的类型输出

【问题讨论】:

标签: typescript typescript-typings


【解决方案1】:

这是启用--strictNullChecks 的正确且明确定义的结果。

TypeScript 的设计师 Anders Hejlsberg 在this talk 中精彩地解释了它。它在最后 3 日,但绝对值得观看整个演讲。

简而言之,--strictNullChecks。更改类型之间的关系,使值 nullundefined 分别是两个新的单例类型 nullundefined 的成员,并且不再是任何其他类型的组成部分。

因此,给定T | undefined,第一个签名

test(a: T)

不再是候选人。此外,至关重要的是,第二个签名

test(a: undefined)

也不再是候选人,因为它的参数可能是 TT 不是 undefined

幸运的是,解决方案实际上代码更少,更容易理解

test(a: T | undefined) {
    return something;
}

联合类型表示a 是属于T 类型和undefined 类型联合的所有可能值集合的成员。

采用所有可能参数类型的联合类型的单个签名与一组不同的重载签名之间的主要区别在于参数和返回类型的相关性。

具体来说,

declare function f(x: A): B;
declare function f(x: T): U;

不等于

declare function f(x: A | T): B | U;

在接受和拒绝的方面有所不同。以playground 为例。

但是,在没有 --strictNullChecks 的情况下,重载仅在使用已知为 undefined 的值时才有意义,因为每个 T 都隐含为 T | undefined

您可以返回使用重载,从而重新控制参数类型以返回类型相关性,但只能通过在调用站点引入额外信息,例如

test2(b?: T) {
    if (b) { 
      return this.test(b);
    } else {
      return this.test(b);
    }
}

【讨论】:

  • 感谢您的解释!对于Tundefined 的每种情况,我想定义一个唯一的返回类型,因此在原始情况下使用重载。这可能吗?
  • 编辑了原始帖子以显示所需的输出类型。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-09-15
  • 2019-09-30
相关资源
最近更新 更多