TypeScript是否可以将功能作为React prop与功能签名的参数冲突?

时间:2018-10-04 07:48:15

标签: reactjs typescript

为什么TypeScript类型检查器允许使用功能参数与定义不严格匹配的prop?

具体来说,我定义了一个函数callbackImpl = (str: string): number,并将其作为定义为callback(parameter: string | undefined): number;的React prop参数给出了。

这对我来说是不直观的,而且我认为这很危险!

但是!调用正确的callbackImpl(undefined)无效。

完整的示例:

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>
        );
    }
}

我在"strict": true,中设置了tsconfig.json

这是一个更完整的tsconfig.json列表,其中省略了一些本地内容。

{
  "compilerOptions": {
    "outDir": "./dist/",
    "sourceMap": true,
    "noImplicitAny": true,
    "moduleResolution": "node",
    "module": "esnext",
    "allowSyntheticDefaultImports": true,
    "target": "es6",
    "jsx": "react",
    "allowJs": true,
    "strict": true,
    "noEmitOnError": true,
    "plugins": [],
    "baseUrl": "./",
    "paths": {
      // Omitted
    },
    "lib": [
      "es2017", // Object.entries support
      "dom"
    ],
    "types": ["gapi", "gapi.auth2", "node"]
  },
  "exclude": [
    "node_modules"
  ]
}

我做错什么了吗?我的tsconfig设置错误吗?我误会了吗?

谢谢!

编辑

Titian Cernicova-Dragomir回答后的其他资源

  • Strict Function Types,如TS 2.6发行说明所述。描述严格的函数类型检查未涵盖方法。

1 个答案:

答案 0 :(得分:4)

您是对的,这是不安全的。允许这种行为简化从JS到TS的迁移是有道理的。您可以使用strictFunctionTypes选择禁止这样做的好消息。

例如此代码

declare const callbackImpl: (str: string) => number

let callback: (parameter: string | undefined) => number;

callback = callbackImpl

callback(undefined);

上面的代码使用strictNullChecks进行编译,即使您注意到并非完全安全。但是它将无法同时使用strictNullChecksstrictFunctionTypes

进行编译

注意我假设您尚未使用strictNullChecks,则代码可以按预期工作,因为根据定义,如果没有此选项string|undefinedstring

修改

上面的一般解释是在问题包括实际代码之前发布的。编译器未捕获错误的原因是因为您将回调定义为方法。如果将其定义为函数字段,则编译器将捕获错误。 我仍然不确定为什么参见下文:

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>
        );
    }
}

修改

此行为是设计使然。 -strictFunctionTypes标志不适用于原始PR

中所述的方法
  

更严格的检查适用于所有函数类型,但源于方法或构造函数声明的函数类型除外。专门排除了方法,以确保通用类和接口(例如Array)继续保持大多数协变关系。严格检查方法的影响将是一个重大突破,因为大量泛型类型将变为不变(即使如此,我们可能会继续探索这种更严格的模式)。