reactjs - 在反应 js 应用程序中使用打字稿迭代
问题描述
我有一个使用打字稿的反应应用程序。
interface IFirst {
name: string,
age: number
}
interface ISecond {
name: string,
cars: number,
friends: number
}
type ICommon = IFirst | ISecond;
const Element: React.FC<ICommon> = ({name, age, cars, friends}) => {
return <div>Hello {name} {age}, {cars}, {friends}</div>
}
const Parent = () => {
return <Element name={'J'} age={11}/>
}
export default function App() {
return (
<div className="App">
<Element name={'B'} cars={2} friends={6}/>
<Parent/>
</div>
);
}
我Element
在 2 个不同的组件中使用组件。接下来我要实现的是:如果我将使用App
带有ISecond
接口道具的组件中的组件,那么我应该无法使用IFirst
接口中的其他道具。在我的情况下,我应该无法添加age
道具,并且我应该得到打字错误。当我在中使用组件时应该是相同的逻辑Parent
,在这里我应该无法从ISecond
界面添加道具。我试图在上面的代码中,但我无法管理,并且我在Element
组件悬停时遇到打字稿错误age, cars, friends
。
我上面描述的内容如何?
演示:https ://codesandbox.io/s/busy-fire-d6dw4?file=/src/App.tsx:229-248
解决方案
您不能使用接口联合的解构并期望 ts 在运行时区分哪个接口是相关的。您也不能使用typeof
orinstanceof
在运行时自己动态推断它。
您可以做的是通过将 props 对象转换为某个接口并每次提取相关属性来解构所有属性,例如:
const Element: React.FC<ICommon> = props => {
const {name, age} = props as IFirst;
const {cars, friends} = props as ISecond;
return (...);
}
请注意,您不能name
在同一范围内声明两次,所以我只声明了一次...
如果您想确定您正在处理哪种类型,您可以使用强制转换确定“实际”类型而不会发出任何警告:
if ((props as ISecond).cars !== undefined) {
const {name, cars, friends} = props as ISecond;
}
age
和 也是如此IFirst
。
如果你想做一些更好的练习——我发现了一篇关于TypeScript 中的 Discriminate Unions and Destructuring的文章。
另一种方法是使用is
关键字“添加”道具对象的类型所需的属性,同时确定道具的实际类型:
function hasCars(obj: any): obj is ISecond {
return !!obj && typeof obj === "object" && "cars" in obj;
}
function hasAge(obj: any): obj is IFirst {
return !!obj && typeof obj === "object" && "age" in obj;
}
const Element: React.FC<ICommon> = (props) => {
if (hasCars(props)) {
// props is now exactly of type ISecond
const {name, cars, friends} = props; // This is a valid statement now
props.friends // Also won't cause the red line...
}
else if (hasAge)) {
// Same here but with IFirst
}
}
推荐阅读
- c# - 更新和删除冗余节点树
- typescript - 如何在 Typescript 中表达函数契约?
- javascript - 为什么我作为图像包含的视图之间存在差异?
- php - 我如何知道用户点击了哪个图片?
- ios - 如何从给定日期获取下 n 天的日期
- react-native-navigation - 在 react-native-navigation 中设置标签栏图标颜色
- jmeter - Jmeter BackendListener:如何使用运行时变量
- r - 如何在R中的数字之间添加逗号?
- vagrant - 如何修复 vagrant 中的“无法检索镜像列表”错误?
- c - 我可以在 C 中用 NULL 初始化字符串吗