React中的TypeScript和可重用组件



我正在尝试创建一个可重用的组件,它采用两种不同类型中的一种,我们称它们为Car和Truck,我们从API获得。

type Props = {
data: Car | Truck;
onToggleDataSave: (id: number, isHome: boolean) => void;
isCar: boolean;
};
const Card = ({ data, onToggleDataSave, isCar }: Props) => {
const handleToggleCardSave = (e: SyntheticEvent) => {
e.preventDefault();
isCar
? onToggleDataSave(data.carId, isCar)
: onToggleDataSave(data.truckId, isCar);
};

return (
<h1> Some markup </h1>
);
};

这在JavaScript中工作,因为我在尝试访问其属性之前检查我的data是否为汽车,但TS对此不满意,因为它说Truck没有carId属性。

我如何在满足TypeScript的同时保持组件的可重用性?

这并不需要任何额外的检查,只需要更好的类型。

type Car = { carId: number }
type Truck = { truckId: number }
type PropsInCommon = {
onToggleDataSave: (id: number, isHome: boolean) => void;
}
type Props = ({
data: Car;
isCar: true;
} | { 
data: Truck;
isCar: false
}) & PropsInCommon;
const Card = ({ data, onToggleDataSave, isCar }: Props) => {
const handleToggleCardSave = (e: SyntheticEvent) => {
e.preventDefault();
isCar
? onToggleDataSave(data.carId, isCar)
: onToggleDataSave(data.truckId, isCar);
};

return (
<h1> Some markup </h1>
);
};

尽管这可能感觉有点迂回,但感觉它不需要类型保护就能表达你的意图。

这段代码实际上告诉编译器isCar: true, data: Truck状态使用联合操作符是无效的。

这可以更好地告知编译器该类型的期望值:

isCartrue时,data类型为Car

其他答案看起来不错,但是您真的需要传递给组件的isCar道具吗?您可以通过检查类型来确定它是否是汽车,如下所示:

type Car = {
carId: number;
};

type Truck = {
truckId: number;
};

interface Props {
vehicle: Car | Truck;
}

const isCar = (v: any): v is Car => {
return v.carId !== undefined;
};

const Vehicle = (props: Props) => {

return (
<div>
{isCar(props.vehicle) ? props.vehicle.carId : props.vehicle.truckId}
</div>
);
};

export default function App() {
const vehicle = { carId: 1 } as Car;

return (
<div className="App">
<h1>Vehicle</h1>
<Vehicle vehicle={vehicle} />
</div>
}
type Props = {
data: Car | Truck;
onToggleDataSave: (id: number, isHome: boolean) => void;
isCar: boolean;
};
function carGuard(_data: Car | Truck, isCar: boolean): _data is Car {
return isCar;
}
export const Card = ({ data, onToggleDataSave, isCar }: Props): JSX.Element => {
const handleToggleCardSave = (e: SyntheticEvent): void => {
e.preventDefault();
if (carGuard(data, isCar)) {
onToggleDataSave(data.carId, isCar);
} else {
onToggleDataSave(data.truckId, isCar);
}
};
return <h1> Some markup </h1>;
};

最新更新