Reactjs TypeScript允许函数作为与函数签名的in-param冲突的React prop?

Reactjs TypeScript允许函数作为与函数签名的in-param冲突的React prop?,reactjs,typescript,Reactjs,Typescript,为什么TypeScript类型检查器允许带有与定义不完全匹配的函数参数的道具 具体来说,我定义了一个函数callbackImpl=(str:string):number,并将其作为React prop参数提供,该参数定义为callback(parameter:string | undefined):number,这令人惊讶地有效 这对我来说是不直观的,在我看来是相当危险的 但是!调用callbackImpl(未定义)不起作用,我认为这是正确的 一个完整的例子: import React from

为什么TypeScript类型检查器允许带有与定义不完全匹配的函数参数的道具

具体来说,我定义了一个函数
callbackImpl=(str:string):number
,并将其作为React prop参数提供,该参数定义为
callback(parameter:string | undefined):number,这令人惊讶地有效

这对我来说是不直观的,在我看来是相当危险的

但是!调用
callbackImpl(未定义)
不起作用,我认为这是正确的

一个完整的例子:

import React from "react";

interface Props {
    callback(parameter: string | undefined): number;
}

class A extends React.Component<Props> {
    componentDidUpdate() {
        this.props.callback(undefined);
    }
}

class B extends React.Component {

    private callbackImpl = (str: string): number => {
        // Will crash if str is undefined
        return str.length;
    };

    // THIS IS NOT ALLOWED! And rightly so!
    private callLocalWithUndefined() {
        // TS2345: Argument of type 'undefined' is not assignable to parameter of type 'string'.
        this.callbackImpl(undefined);
    }

    render() {
        return (
            <React.Fragment>
                <A
                    // This is obviously just as illegal as what happens in callLocalWithUndefined,
                    // since callbackImpl explicitly does not accept undefined as the first parameter,
                    // but no type errors here!?
                    callback={this.callbackImpl}
                />
            </React.Fragment>
        );
    }
}
我做错什么了吗?我的tsconfig设置是否错误?我是不是误解了什么

谢谢

编辑 Titian Cernicova Dragomir回答后的其他资源

  • 如TS 2.6发行说明所述。描述严格的函数类型检查不包括方法

    • 你说得对,这是不安全的。允许这种行为来简化从JS到TS的迁移是有道理的。好消息是,您可以通过使用
      strictFunctionTypes
      选择不允许这种行为

      例如,此代码

      declare const callbackImpl: (str: string) => number
      
      let callback: (parameter: string | undefined) => number;
      
      callback = callbackImpl
      
      callback(undefined);
      
      上面的代码使用
      strictNullChecks
      编译,尽管它并不像您所注意到的那样是完全类型安全的。但它无法同时使用
      strictNullChecks
      strictFunctionTypes

      注意我假设您已经在使用
      stricnullchecks
      ,如果您没有,那么代码将按预期工作,因为没有此选项
      string |未定义的
      根据定义就是
      string

      编辑

      上面的一般解释是在问题包含实际代码之前发布的。编译器没有捕获错误的原因是您将回调定义为一个方法。如果将其定义为函数字段,编译器将捕获错误。我仍然不确定为什么会看到以下内容:

      interface Props {
          callback: (parameter: string | undefined) => number;
      }
      
      class A extends React.Component<Props> {
          componentDidUpdate() {
              this.props.callback(undefined);
          }
      }
      
      class B extends React.Component {
      
          private callbackImpl = (str: string): number => {
              // Will crash if str is undefined
              return str.length;
          };
      
      
          render() {
              return (
                  <React.Fragment>
                      <A
                        // Error now
                          callback={this.callbackImpl}
                      />
                  </React.Fragment>
              );
          }
      }
      
      界面道具{
      回调:(参数:字符串|未定义)=>number;
      }
      类扩展了React.Component{
      componentDidUpdate(){
      this.props.callback(未定义);
      }
      }
      类扩展了React.Component{
      private callbackImpl=(str:string):number=>{
      //如果str未定义,将崩溃
      返回str.length;
      };
      render(){
      返回(
      

      更严格的检查适用于所有函数类型,但源自方法或construcor声明的函数类型除外。排除方法是为了确保泛型类和接口(如数组)继续以协变的方式进行关联。严格检查方法的影响将是一个更大的突破性变化,因为大量泛型类型将变得不变(即使如此,我们可能会继续探索这种更严格的模式)


      我更新了我的答案,以反映添加的代码。感谢更新。如果你发现为什么它与函数字段而不是方法一起工作,我将非常高兴=)谢谢!这是一个相当谨慎的警告-不直观且危险。我个人等不及WebAssembly让我们摆脱荒谬的JavaScript遗产。
      interface Props {
          callback: (parameter: string | undefined) => number;
      }
      
      class A extends React.Component<Props> {
          componentDidUpdate() {
              this.props.callback(undefined);
          }
      }
      
      class B extends React.Component {
      
          private callbackImpl = (str: string): number => {
              // Will crash if str is undefined
              return str.length;
          };
      
      
          render() {
              return (
                  <React.Fragment>
                      <A
                        // Error now
                          callback={this.callbackImpl}
                      />
                  </React.Fragment>
              );
          }
      }