首页 > 解决方案 > TypeScript:如何确保功能组件的两个道具(数组)具有相同的长度?

问题描述

我正在尝试在反应中制作一个功能组件,它接受两个单独的字符串作为道具。有没有办法使用 TypeScript 确保这两个数组必须具有相同的长度?换句话说,当我们在其他组件中使用这个组件时,除非 props 的长度相同,否则我们会收到错误。

举一个简单的例子,想象一下这样的事情:

export const TableView = ({ s1, s2 }: { s1: string[]; s2: string[] }) => {
  return (
    <table>
      <thead>
        <tr>
          {s1.map((s, index) => {
            return <th>{s1[index]}</th>;
          })}
        </tr>
      </thead>
      <tbody>
        <tr>
          {s2.map((s, index) => {
            return <td>{s2[index]}</td>;
          })}
        </tr>
      </tbody>
    </table>
  );
};

我想确保在将它与不同长度的字符串一起使用时看到错误。

      <TableView s1={["1", "2", "3"]} s2={["1", "2", "3", "4"]} />
      {/* show an error here */}


标签: javascriptreactjstypescript

解决方案


为了让编译器跟踪输入参数的s1s2元素的长度,你应该在 的类型中进行TableView 泛型s1,然后用它来检查s2。因此,调用签名TableView应该如下所示:

<T extends string[]>({ s1, s2 }: {
    s1: [...T];
    s2: [...{ [I in keyof T]: string; }];
}) => JSX.Element

这里我们说的T是一些数组类型的字符串,s1本质上是 type T。该语法[...T]使用可变元组类型语法给编译器一个提示,我们希望它T作为元组类型而不只是数组类型来解释。元组类型具有已知的顺序和长度,而普通数组类型则没有。你关心长度,所以你想要一个元组类型。

如果我们也可以写[...T]for那就太好了s2,但不幸的是,编译器倾向于将 的元素推断T为字符串文字类型,例如"1"and"2"而不是string. s2如果是这样,那么这样说[...T]将限制 的每个元素s2必须完全等于 的相应元素s1。我们不想拒绝{s1: ["1", "2"], s2: ["2", "1"]},所以我们不能那样做。

因此,我们说这s2是一个映射元组类型,具有相同数量的元素,s1但每个值类型都可以是 a string

这就是你想要的约束。


让我们测试一下:

<TableView s1={["1", "2", "3"]} s2={["4", "3", "2", "1"]} /> // error!
// --------------------------➨ ~~
// Source has 4 element(s) but target allows only 3.

<TableView s1={["1", "2", "3"]} s2={["4", "3", "2"]} /> // okay

看起来挺好的!

Playground 代码链接


推荐阅读