我正在尝试创建一个可重用的组件,它采用两种不同类型中的一种,我们称它们为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
状态使用联合操作符是无效的。
这可以更好地告知编译器该类型的期望值:
当isCar
为true
时,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>;
};