首页 > 解决方案 > 在反应 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

标签: reactjs

解决方案


您不能使用接口联合的解构并期望 ts 在运行时区分哪个接口是相关的。您也不能使用typeoforinstanceof在运行时自己动态推断它。

您可以做的是通过将 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
  }
}

推荐阅读