无法调用可能是“未定义”的对象。ts(2722)

kus*_*lvm 31 typescript reactjs

我有一个按钮组件。我只是将onClick我定义的许多可选道具中的一个道具传递给它:

const Button = (props: ButtonProps) => {
    const handleClick: React.MouseEventHandler<HTMLButtonElement | HTMLAnchorElement> = e => {
        props.onClick(e);
    }
    return (
        <StyledButton onClick={handleClick}>
            {props.children}
        </StyledButton>
    );
};
Run Code Online (Sandbox Code Playgroud)

然后我像这样使用它:

<Button onClick={(e) => {
    console.log(e);
}}>Click me!</Button>
Run Code Online (Sandbox Code Playgroud)

现在如何根据所提到的错误,对象可能是未定义的?我清楚地将函数传递给它,并且根据类型定义也是如此。所以,我将一个对象传递给它。够简单!

...
onClick?: React.MouseEventHandler<HTMLElement>
...
Run Code Online (Sandbox Code Playgroud)

我最近在这个项目中添加了一些更严格的检查,相关的检查是:

"strictFunctionTypes": true,
"strictNullChecks": true
Run Code Online (Sandbox Code Playgroud)

strict:true 已经存在,此错误从未发生。

这里有什么问题?

更新 - 添加的类型

export interface IBaseButtonProps {
    type?: ButtonType;
    disabled?: boolean;
    size?: ButtonSize;
    block?: boolean;
    loading?: boolean | { delay?: number };
    icon?: string;
    className?: string;
    prefixCls?: string;
    children?: React.ReactNode;
}

export type AnchorButtonProps = {
    href: string,
    target?: string,
    onClick: React.MouseEventHandler<HTMLElement>
} & IBaseButtonProps & Omit<React.AnchorHTMLAttributes<any>, 'type' | 'onClick'>;


export type NativeButtonProps = {
    onClick: React.MouseEventHandler<HTMLElement>,
    htmlType?: ButtonHTMLType
} & IBaseButtonProps & Omit<React.ButtonHTMLAttributes<any>, 'type' | 'onClick'>;

export type ButtonProps = Partial<AnchorButtonProps & NativeButtonProps>
Run Code Online (Sandbox Code Playgroud)

笔记:

可能的解决方案是解构道具并添加默认道具。或者defaultProps从 React使用。但不确定我是否真的需要使用 Typescript。

Sha*_*tin 18

现在如何根据所提到的错误,对象可能是未定义的?[原文]

使用Partial<T>aroundexport type ButtonProps = Partial<AnchorButtonProps & NativeButtonProps>原因onClick是可选的。当我们使用Partial<T>,所有属性都接收?并因此成为可选的,这意味着它们都可以是未定义的。

有两种修复方法:一种是ButtonPropsonClick可选的保持相同,并onClick在调用之前检查它的定义(修复 1);另一种是改变ButtonProps使onClick必需的(修复 2 和 3)。

修复 1: onClick仍然是可选的

使用ButtonProps您已有的 ,然后onClick在调用之前检查已定义的 。这就是antd在您在注释中链接的代码中所做的。

const Button = (props: ButtonProps) => {
  const handleClick: React.MouseEventHandler<
    HTMLButtonElement | HTMLAnchorElement
  > = e => {
    if (props.onClick) props.onClick(e); // works
  };
};
Run Code Online (Sandbox Code Playgroud)

修复 2: onClick成为必需

ButtonProps通过不将 应用于Partial来更改NativeButtonProps

type ButtonProps1 = Partial<AnchorButtonProps> & NativeButtonProps;

const Button1 = (props: ButtonProps1) => {
  const handleClick: React.MouseEventHandler<
    HTMLButtonElement | HTMLAnchorElement
  > = e => {
    props.onClick(e); // works
  };
};
Run Code Online (Sandbox Code Playgroud)

修复 3: onClick变得需要

定义一个RequireKeys类型,它允许您指定非可选的键。

const Button = (props: ButtonProps) => {
  const handleClick: React.MouseEventHandler<
    HTMLButtonElement | HTMLAnchorElement
  > = e => {
    if (props.onClick) props.onClick(e); // works
  };
};
Run Code Online (Sandbox Code Playgroud)

映射类型的答案:删除可选修饰符包含有关我如何定义RequireKeys<T>.


kis*_*ore 10

只是一个明确的答案

if (props.onClick) props.onClick(e);

如果您正在定义一个函数 props 并希望它是可选的,请将其定义为,

export type ButtonProps = {
  function?: () => void;
};
Run Code Online (Sandbox Code Playgroud)

说明: 如果您想使用函数作为 props,则可能在某些情况下您希望传递该函数(作为 props),而在其他情况下您可能不想传递它。

例如,

通用代码在哪里调用<Home/>组件,例如index.ts/index.js

function myfunction(){
  //do something
  alert("hello")
}

return (
  <>
     <Home myfunction={myfunction}/>    //passing prop
     <Home/>                            // not passing
  </>
)

Run Code Online (Sandbox Code Playgroud)

在 JS 中,home.js

export default function Home({myfunction}) {
  const const1 = "Hello World"
  return (
    //do something
    myfunction();      //IMPORTANT line
  )
}
Run Code Online (Sandbox Code Playgroud)

现在,它几乎相当于 TS,home.ts

在 TS 中,我们定义了一切的类型。因此,在这种情况下,我们还必须定义myfunction我们传递的该函数的类型。

因此,对于这个函数,我们意识到,

  • 它没有接收参数,所以()(空括号)就足够了,如果有任何参数,我们还需要为它们定义类型。
  • 不返回任何内容,因此返回类型void
export type HomeProps = {
  myfunction?: () => void;
};

export default function Home({ myfunction }: HomeProps) {
  const const1 = "Hello World"
  return (
    //do something
    if (myfunction) myfunction();      //IMPORTANT line
  )
}
Run Code Online (Sandbox Code Playgroud)

提示:以上答案


Muk*_*rya 8

逻辑运算符 AND (&&) 返回它找到的第一个假操作数的值,或者如果所有值均为真则返回最后一个操作数的值 ( Source )。因此,我们可以简单地写:

 (props.onClick && props.onClick(e));
Run Code Online (Sandbox Code Playgroud)

  • 虽然此代码块可以回答这个问题,但最好您能提供一些解释为什么这样做。 (7认同)

Tit*_*toh 7

我正在创建自己的自定义 MUI 按钮,这就是我的做法。

interface ButtonTypes {
  handleClick?: React.MouseEventHandler<HTMLButtonElement> | undefined
}
Run Code Online (Sandbox Code Playgroud)

在按钮组件上

<LoadingButton
  onClick={(e) =>handleClick && handleClick(e)}
>
  {"Send"}
</LoadingButton>
Run Code Online (Sandbox Code Playgroud)

如果您使用的是 VScode,请将鼠标悬停在该OnClick属性上,您应该会看到预期的类型。


chr*_*arx 5

使用 Typescript 3.7+,您还可以使用可选链来调用可选的 prop 方法:

const Button = (props: ButtonProps) => {
  const handleClick: React.MouseEventHandler<
    HTMLButtonElement | HTMLAnchorElement
  > = e => {
    props.onClick?.(e); // works
  };
};
Run Code Online (Sandbox Code Playgroud)

您可以阅读有关使用可选链接的更多信息 - https://www.stefanjudis.com/today-i-learned/optional-chaining-helps-to-avoid-undefined-is-not-a-function-exceptions/

  • 这很巧妙,比例外的答案好多了! (5认同)