Typescript 和 React defaultProps 仍然被视为可能未定义

Don*_*Don 8 typescript reactjs

interface PageProps {
    foo?: Function;
    bar: number;
}

export class PageComponent extends React.Component<PageProps, {}> {
    public static defaultProps: Partial<PageProps> = {
        foo: () => alert('Did foo')
    };

    private doFoo() {
        this.props.foo(); // Typescript Error: Object is possibly 'undefined'
    }

    public render(): JSX.Element {
        return (
            <div>
                <span>Hello, world! The number is {this.props.bar}</span>
                <button onClick={() => this.doFoo()}>Do the Foo</button>
            </div>
        );
    }
}
Run Code Online (Sandbox Code Playgroud)

有没有办法告诉 Typescriptprops.foo总是定义?

有一个非常好的SO 问答,讨论了如何正确定义组件上 props 的类型。它甚至讨论了如何让 TS 了解无状态defaultProps组件。

然而,Typescript 仍然会在常规组件定义中抱怨你的 props 可能未定义(如我上面的示例所示)。

您可以使用 bang ( this.props.foo!()) 来调用它,这可以防止 TS 引发错误,但它也可以防止对您传入的任何内容进行任何类型的检查。在上面的示例中,这没什么大不了的。在更复杂的代码中,它已经咬住了我。

所以我目前正在实施这样的事情:

private doFoo() {
    if (this.props.foo) this.props.foo();
}
Run Code Online (Sandbox Code Playgroud)

这有一个缺点,我认为这个缺点相当重要:它使我的代码有点混乱。实际上,我总是想调用this.props.foo(),但似乎在不更仔细地研究该类的情况下,在某些情况下该doFoo方法内部不会发生任何事情。(是的,我可以添加一条注释,解释这if只是为了让 Typescript 感到高兴,但我宁愿我的代码在可以的情况下自己说话。)

当我实际上需要从this.props.foo().

我目前正在使用 @types/react 作为我的类型定义。

Pie*_*Duc 7

因此,编译器说该对象可能是undefined. 你更清楚事实并非如此,所以你只想写this.props.foo()。正确的方法是使用空断言类型运算符

this.props.foo!()
Run Code Online (Sandbox Code Playgroud)

如果你说这之前已经困扰过你,那么那是你自己没有检查它的错:),这意味着编译器是正确的,该对象本来可以是undefined。如果有可能undefined,您应该始终检查它。也许您喜欢该声明的更简短版本if?少了一个字符:

private doFoo() {
  this.props.foo && this.props.foo();
}
Run Code Online (Sandbox Code Playgroud)

或使用 typescript >= 3.8:

private doFoo() {
  this.props.foo?.();
}
Run Code Online (Sandbox Code Playgroud)

另一方面,您可以创建一个额外的接口,extends其中PageProps. 为了好玩,我们称它为PagePropsFilled

interface PagePropsFilled extends PageProps {
    foo: Function;
}
Run Code Online (Sandbox Code Playgroud)

您现在可以将您的设置this.propsPagePropsFilled,它不会再向您显示错误