如何定义组件的相互依赖类型Props



我试图对我的React Typescript项目进行一些简化,但我在如何正确注释类型上遇到了困难。下面是我正在使用的代码的一个精简示例:

https://codesandbox.io/s/working-example-qc5cq

// WORKING EXAMPLE
import * as React from "react";
import { render } from "react-dom";
const App: React.FC = () => {
const handleClick = (value: string | number): void => {
if (typeof value === "string") {
// Do some string logic...
console.log(`String: ${value}`);
} else if (typeof value === "number") {
// Do some number logic
console.log(`Number: ${value}`);
}
};
return (
<div>
<Button handleClick={handleClick} value="Hello" />
<Button handleClick={handleClick} value={42} />
</div>
);
};
interface Props {
handleClick: (value: string | number) => void;
value: string | number;
}
const Button: React.FC<Props> = ({ handleClick, value }) => (
<button onClick={(): void => handleClick(value)}>{value}</button>
);
const rootElement = document.getElementById("root");
render(<App />, rootElement);

我想做的是将handleClick-函数拆分为两个独立的函数;一个用于处理string,一个用于用于处理number。当我尝试为Button-组件键入Props时,问题就出现了。以下是我目前的处境:

https://codesandbox.io/s/wip-example-fied2

// WIP
import * as React from "react";
import { render } from "react-dom";
const App: React.FC = () => {
const handleStringClick = (string: string) => {
// Do some string logic...
console.log(`String: ${string}`);
};
const handleNumberClick = (number: number): void => {
// Do some number logic
console.log(`Number: ${number}`);
};
return (
<div>
<Button handleClick={handleStringClick} value="Hello" />
<Button handleClick={handleNumberClick} value={42} />
</div>
);
};
interface StringProps {
handleClick: (string: string) => void;
value: string;
}
interface NumberProps {
handleClick: (number: number) => void;
value: number;
}
type Props = StringProps | NumberProps;
const Button: React.FC<Props> = ({ handleClick, value }) => (
<button onClick={(): void => 🚨handleClick(value)}>{value}</button>
);
const rootElement = document.getElementById("root");
render(<App />, rootElement);

我收到的错误在handleClick(value):上

类型为"ReactText"的参数不可分配给类型为的参数"从不"。类型"string"不可分配给类型"never"。ts(2345(

这是可以理解的,因为value的类型被解释为string | number(实际上是ReactText,但这是React的缩写(,并且handleClick的任何版本都不能处理这种情况。


所以问题是,我能以某种方式注释Props,使handleClick取决于value的类型吗?换句话说,如果我将value设置为number,我能让Typescript理解并强制我传入handleClick(number)函数吗?如果我的心态或我试图实现的目标有点缺陷,请随时为我指明更好的方向。

实现这一点的一种方法是使Button通用:
type Props<T extends string | number> = {
handleClick: (argument: T) => void;
value: T;
}
const Button= <T extends string | number,>({ handleClick, value }: Props<T>) => (
<button onClick={(): void => handleClick(value)}>{value}</button>
);
<Button handleClick={arg => { /** `arg` is of type `42` */}} value={42} />

感谢Karol的回答!我能够根据你的建议调整我的代码;我像您一样离开了Props,然后扩展了您的Button代码以获得返回类型:

const Button = <T extends string | number>({
handleClick,
value
}: Props<T>): JSX.Element => (
<button onClick={(): void => handleClick(value)}>{value}</button>
);

还发现了一个很好的来源:在TypeScript 中将泛型传递给JSX元素

最新更新