reactjs 获取一个类型以依赖另一个类型;类型条件

sd2nnvve  于 2022-12-12  发布在  React
关注(0)|答案(1)|浏览(94)

我有一个Test组件,它必须接受一个one属性,其中对象必须有一个a字段,但只有一个id字段 * 如果 * 没有提供two属性。如果提供了two属性,则one属性的对象必须没有id字段。
如何才能做到这一点?我能得到的最接近的方法是使用以下界面:

interface Test {
  one: {
    a: string;
    id?: number;
  };
  two?: number;
}

显然,它不会正常工作,因为id字段和two属性只是设置为可选,而不是相互调节。
下面是我构建的演示:

export default function App() {
  return (
    <div>
      <Test
        one={{
          a: 'valid example with id and no two prop',
          id: 5,
        }}
      />

      <Test
        one={{
          a: 'valid example with two prop and no id field',
        }}
        two={9}
      />

      <Test
        one={{
          a: 'should have id or two prop; needs to error',
        }}
      />

      <Test
        one={{
          a: 'cannot have both id field AND two prop; needs to error',
          id: 2,
        }}
        two={5}
      />
    </div>
  );
}

interface Test {
  one: {
    a: string;
    id?: number;
  };
  two?: number;
}

const Test = ({ one, two }: Test): JSX.Element => {
  return <p>test</p>;
};

堆栈 lightning 战演示:https://stackblitz.com/edit/react-ts-2wsnwj?file=App.tsx
我想知道我是否可以这样写类型,但显然不行:

type One = {
  a: string
  id?: number
}

type Two = One.id ? number : null

如有任何建议,我将不胜感激,谢谢

更新:

我刚刚意识到我接受的答案是错误的,因为它仍然期待prop two所有的时间,因此在这个演示中的两个组件的错误(https://stackblitz.com/edit/react-ts-owrj8a?file=App.tsx)。
我试图把它从答案改成这样:

interface A {
  a: string;
}
interface OptionOne {
  one: A & {
    id: number;
  };
  two: never;
}
interface OptionTwo {
  one: A;
  two: number;
}
type FinalType = OptionOne | OptionTwo;

// type Test =
//   | { one: { a: string; id: number } }
//   | { one: { a: string }; two: number };

const Test = ({ one, two }: FinalType): JSX.Element => {
  return <p>test</p>;
};

但它有同样的效果。有人知道解决这个问题的方法吗?
未提供prop two时的错误:

Type '{ one: { a: string; }; }' is not assignable to type 'IntrinsicAttributes & FinalType'.
  Property 'two' is missing in type '{ one: { a: string; }; }' but required in type 'OptionTwo'
vwhgwdsa

vwhgwdsa1#

使Test成为涵盖所有可接受状态的联合类型:

type Test = {one: {a: string; id: number}} | 
            {one: {a:string}; two:number}

在OP评论后编辑:
你现在面临的问题并不奇怪,TypeScript不允许你从props反结构two,因为你已经告诉过在某些情况下这个属性不存在。
在这种情况下,您可以手动检查two字段是否存在,如果存在,则使用它。

const Test = (props: FinalType): JSX.Element => {
  if ('two' in props) {
    return <p>{props.two}</p>;
  }
  return <p>test</p>;
};

现在错误已经消失了。

相关问题