【问题标题】:Typescript overload arrow function is not working打字稿重载箭头功能不起作用
【发布时间】:2019-09-30 06:03:59
【问题描述】:

(我正在使用严格的空值检查)

我有以下箭头函数,具有重载类型:

    type INumberConverter = {
      (value: number): number;
      (value: null): null;
    };
    const decimalToPercent: INumberConverter = (value: number | null): number | null => {
      if (!value) {
        return null;
      }
      return value * 100;
    };

根据其他问题 (Can I use TypeScript overloads when using fat arrow syntax for class methods?) 的理解,这应该是有效的。永远不会出现以下错误:

TS2322: Type '(value: number | null) => number | null' is not assignable to type 'INumberConverter'.   Type 'number | null' is not assignable to type 'number'.     Type 'null' is not assignable to type 'number'

如果我定期编写这个函数(使用function 关键字):

    function decimalToPercent(value: null): null;
    function decimalToPercent(value: number): number;
    function decimalToPercent(value: number | null): number | null {
      if (!value) {
        return null;
      }
      return value * 100;
    }

它可以正常工作。

我需要使用箭头函数,所以 this 不会改变,我需要这个重载,所以 typescript 知道 decimalToPercent(1) 不能为空。

为什么它不能按照我的方式工作,我该如何解决?

【问题讨论】:

    标签: typescript overloading arrow-functions


    【解决方案1】:

    重载签名和实现签名之间的兼容性规则比赋值要宽松得多。

    在这种情况下,您尝试将可能返回 null 的函数分配给具有禁止返回 null ((value: number): number;) 的重载的函数。编译器会正确地发现这令人不安。对于重载,由于签名和实现都是作为一个单元编写的,编译器假定“你知道你在做什么”(正确与否)。

    您可以通过多种方式解决它:

    你可以使用类型断言,虽然你会失去大多数类型检查的实现,签名兼容性:

    type INumberConverter = {
      (value: number): number;
      (value: null): null;
    };
    const decimalToPercent = ((value: number | null): number | null => {
      if (!value) {
        return null;
      }
      return value * 100;
    }) as INumberConverter;
    

    您也可以像以前的ES5 一样使用常规的function 并捕获this,尽管这种解决方案意味着复制大量的函数签名:

    type INumberConverter = {
      (value: number): number;
      (value: null): null;
    };
    
    class X {
        decimalToPercent: INumberConverter;
        multiper = 100;
        constructor() {
            let self = this;
            function decimalToPercent(value: number): number;
            function decimalToPercent(value: null): null;
            function decimalToPercent(value: number | null): number | null {
                if (!value) {
                    return null;
                }
                // use self
                return value * self.multiper;
            };
            this.decimalToPercent = decimalToPercent;
        }
    }
    

    或者可能最简单的解决方案是在构造函数中使用bind并将函数编写为常规方法:

    class X {
    
        decimalToPercent(value: number): number;
        decimalToPercent(value: null): null;
        decimalToPercent(value: number | null): number | null {
            if (!value) {
                return null;
            }
            return value * this.multiper;
        };
        multiper = 100;
        constructor() {
            this.decimalToPercent = this.decimalToPercent.bind(this);
        }
    }
    

    【讨论】:

    • “编译器会正确地发现这个问题”——你错了。这是你的假设。这应该是一个错误,应该修复。这是完全等价的。
    猜你喜欢
    • 2017-01-04
    • 2020-03-28
    • 1970-01-01
    • 2018-09-29
    • 1970-01-01
    • 1970-01-01
    • 2018-09-30
    • 1970-01-01
    相关资源
    最近更新 更多