我有一个按钮组件。我只是通过了我定义的许多可选道具中的一个onClick
道具。
const Button = (props: ButtonProps) => {
const handleClick: React.MouseEventHandler<HTMLButtonElement | HTMLAnchorElement> = e => {
props.onClick(e);
}
return (
<StyledButton onClick={handleClick}>
{props.children}
</StyledButton>
);
};
然后我像这样使用它
<Button onClick={(e) => {
console.log(e);
}}>Click me!</Button>
现在根据所提到的错误,对象怎么可能不确定?我显然是根据类型定义将函数传递给它。因此,我正在将一个对象传递给它。很简单!
...
onClick?: React.MouseEventHandler<HTMLElement>
...
我最近在这个项目中添加了一些更严格的检查,相关的检查是
"strictFunctionTypes": true,
"strictNullChecks": true
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>
注释-
可能的解决方案是破坏道具并添加默认道具。或者使用React的defaultProps。但是不确定我是否真的需要Typescript。
答案 0 :(得分:1)
在 Typescript 3.7+ 中,您还可以使用可选链来调用可选的 prop 方法:
const Button = (props: ButtonProps) => {
const handleClick: React.MouseEventHandler<
HTMLButtonElement | HTMLAnchorElement
> = e => {
props.onClick?.(e); // works
};
};
您可以阅读有关使用可选链的更多信息 - https://www.stefanjudis.com/today-i-learned/optional-chaining-helps-to-avoid-undefined-is-not-a-function-exceptions/
答案 1 :(得分:0)
现在根据所提到的错误,对象怎么可能不确定? [原文]
在Partial<T>
周围使用export type ButtonProps = Partial<AnchorButtonProps & NativeButtonProps>
导致onClick
是可选的。当我们使用Partial<T>
时,所有属性都将接收?
并因此成为可选属性,这意味着所有属性都可以不确定。
有两种解决方法:一种是将ButtonProps
与onClick
保持为可选,并在调用之前检查onClick
是否已定义(修复1);另一种是更改ButtonProps
以使onClick
为必需项(修复2和3)。
onClick
仍然是可选的使用您已经拥有的ButtonProps
,然后在调用之前检查onClick
是否已定义。这是您在注释中链接的代码中的what antd does。
const Button = (props: ButtonProps) => {
const handleClick: React.MouseEventHandler<
HTMLButtonElement | HTMLAnchorElement
> = e => {
if (props.onClick) props.onClick(e); // works
};
};
onClick
通过不将ButtonProps
应用于Partial
来更改NativeButtonProps
:
type ButtonProps1 = Partial<AnchorButtonProps> & NativeButtonProps;
const Button1 = (props: ButtonProps1) => {
const handleClick: React.MouseEventHandler<
HTMLButtonElement | HTMLAnchorElement
> = e => {
props.onClick(e); // works
};
};
onClick
也成为必需定义RequireKeys
类型,使您可以指定非可选的键。
type RequireKeys<T, TNames extends keyof T> = T &
{ [P in keyof T]-?: P extends TNames ? T[P] : never };
type ButtonProps2 = RequireKeys<ButtonProps, "onClick">;
const Button2 = (props: ButtonProps2) => {
const handleClick: React.MouseEventHandler<
HTMLButtonElement | HTMLAnchorElement
> = e => {
props.onClick(e); // works
};
};
Mapped Types: removing optional modifier的答案提供了有关我如何定义RequireKeys<T>
的更多信息。
答案 2 :(得分:0)
一个明确的答案
if (props.onClick) props.onClick(e);
如果您要定义一个函数props并希望它是可选的,请将其定义为
export type ButtonProps = {
function?: () => void;
};
说明: 如果您想使用某个函数作为道具,则可能会有某些情况想要传递该函数(作为道具),而有些情况下则不想传递该函数。
例如,
在公共代码中调用
<Home/>
组件,例如 index.ts / index.js
function myfunction(){
//do something
alert("hello")
}
return (
<>
<Home myfunction={myfunction}/> //passing prop
<Home/> // not passing
</>
)
在JS中, home.js
export default function Home({myfunction}) {
const const1 = "Hello World"
return (
//do something
myfunction(); //IMPORTANT line
)
}
现在,它在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
)
}
提示:以上答案
答案 3 :(得分:0)
?.call(this: unknown, ...args: any[])
或?.apply(this: unknown, args: any[])
方法所以,让我们想象下一个声明
type callback = ((x: number, y: number) => number) | null;
let a: callback;
let b: callback;
a = (x, y) => x + y; // it works with arrow functions
b = function (x, y) { // and normal functions
return x + y;
};
function x(cb1: callback, cb2: callback) {
console.log(cb1?.call(0, 5, 6)); // in this case you
console.log(cb2?.call(0, 5, 6)); // cant invoke cb1() or cb2()
console.log(cb1?.apply(0, [5, 6])); // but you can use call or apply
console.log(cb2?.apply(0, [5, 6])); // where first parameter can be any value
}
x(a, b); // 11 11 11 11
class C {
public f?: callback;
public setF() {
this.f = (x, y) => {
return x + y;
};
}
}
const c = new C(); // same with objects
c.setF();
console.log(c?.f?.call(c, 2, 3)); // 5
答案 4 :(得分:0)
(props.onClick && props.onClick(e));
答案 5 :(得分:0)
对于下一个来的任何人。另一种选择是使用类型转换。 喜欢:
props = props as NativeProps
根据我的经验,我使用了一个返回 Partial 类型对象的上下文,我需要进行类型转换来克服未定义的错误。喜欢:
const {setSomething} = useContext(SomePartialContext) as MyContextType