【问题标题】:No error when typescript class implements interface method with incorrect signaturetypescript 类实现签名不正确的接口方法时没有错误
【发布时间】:2020-02-06 05:39:24
【问题描述】:
interface Foo {
  fn1(x: string): void;
}

class Test implements Foo {
  public fn1 (): string {
    return "111"
  }
}

预计会出现错误:Class Test wrongly implements interface Foo

因为函数的签名不正确

没有运气。显示没有任何错误

【问题讨论】:

    标签: typescript


    【解决方案1】:

    这实际上并不是一个错误的签名。可以使用单个参数作为字符串调用它,它会忽略该参数。请记住,这是 Javascript 的工作方式,Typescript 会编译为 Javascript:

    function bar() {
        console.log('bar');
    }
    
    bar('baz'); // no error at runtime in Javascript
    

    同样,接口的签名表明该方法是无效的,这与实际返回字符串的方法兼容。如果调用者认为它是无效的,那么他们将永远不会观察到它返回一个字符串。如果他们认为obj.fn1() 没有返回任何内容,那么没有人会写以下内容:

    let result = obj.fn1(); // why am I assigning the return value of a void method?
    

    因此,尽管有“错误”的参数和返回类型,但该方法实际上可以安全地使用,就好像它接受一个字符串并且不返回任何内容一样,因此它与接口的签名兼容。


    这一切都很好,但是 Typescript 可以 被设计为在此处报告错误,并且错误消息可能对您的示例有所帮助。但是在很多情况下它不会有帮助。考虑这段代码:

    let names = ['Alice', 'Bob', 'Clive'];
    let counts: Record<string, number> = {};
    
    names.forEach(name => counts[name] = 0);
    

    Array.prototype.forEach 的签名表示callbackfn 的类型应该是:

    (value: any, index: number, array: any[]) => void
    

    但是箭头函数的类型是(name: string) =&gt; number。这具有较少的参数和非 void 返回类型。因此,这将与您的示例中的“错误”完全相同。当然,这是forEach的基本正确用法,Typescript抱怨也无济于事。

    【讨论】:

      【解决方案2】:

      Typescript 使用结构类型来确定类型兼容性。对于函数,这意味着您不需要声明和实现具有完全相同的签名,只要编译器可以确定实现可以安全地通过声明调用即可。

      以这种方式考虑示例,

        interface Foo {
        fn1(x: string): void;
      }
      
      class Test implements Foo {
      
        constructor()
        {}
      
        public fn1 (): string {
          return "111"
        }
      }
      
      const fn1: Foo = new Test(); // error, fn1 has parameter, although Test fn1 doesn't expect one
      const fn2: Test = new Test();      
      

      fn1 上出现错误但在fn2 上没有出现错误的原因是,一旦赋值完成,编译器只知道变量的类型而不是你最初分配给它的类型,并将根据实际类型进行检查变量。所以对于fn1 这意味着Foo.fn1 需要一个参数,没有办法知道它不需要。对于fn2,它将检查已知不需要参数的Test.fn1

      如何尝试保护您在 Typescript 中的类型。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2018-02-23
        • 1970-01-01
        • 2019-11-07
        • 2017-11-06
        • 2011-02-10
        • 2022-09-28
        • 2014-10-10
        相关资源
        最近更新 更多