首页 > 解决方案 > 用于反应组件的 Typescript 泛型采用记录数组和键数组

问题描述

我正在尝试创建一个简单的类型化反应组件,用于从对象数组呈现表格。数据输入格式为:

// array of records containing data to render in the table
data = [
  {
    one: 1,
    two: 2,
    three: 3,
  },
  {
    one: 11,
    two: 22,
    three: 33,
  }
]

// subset of keys from the data to render in the table
labels = [
  'one',
  'three',
]

组件如下:

function Table<T extends Record<string, string | number>, K extends Extract<keyof T, string>>({
    labels,
    data
}: {
    labels: K[];
    data: T[];
}) {
    return (
        <table className="table">
            {/* ... */}
        </table>
    );
}

测试它,它似乎只在属性中创建标签时才有效,而不是之前:

// Works
<Table labels={['one']} data={data} />

// Does not work
const labels = ['one']
<Table labels={labels} data={data} />
// Type 'string[]' is not assignable to type '("one" | "two" | "three")'

有谁知道如何修复打字,以便第二种方法有效,而我不必内联创建标签数组?

标签: arraysreactjstypescriptgenerics

解决方案


除非必须,否则打字稿不会推断字符串文字类型。如果你写const labels = ['one'];typescript 会拓宽labelsto的类型string[]

您可以通过as const在 3.4 中使用(尚未发布)来解决此问题,但使用as constwhich 将使 ts 推断出一个只读元组labels

const labels = ['one'] as const; // const labels: readonly ["one"]

在 3.4 之前,我们可以使用显式类型:

const labels:  ["one"] = ['one'];

或者使用辅助函数提示编译器推断字符串文字和元组:

function stringTuple<T extends string[]>(...a: T){
    return a;
}
const labels = stringTuple('one'); // const labels:  ["one"]

推荐阅读