👋
我正在编写一个CSV阅读器程序,该程序将一个头列表作为一个属性(我们将其命名为CsvHeaders
。另一个属性返回一个函数,该函数的参数是一个对象,其键肯定是CsvHeaders
的元素。
type CsvHeaders = readonly string[];
type CsvRow = Record<CsvHeaders[number], string>;
interface ICsvReaderProps {
headers: CsvHeaders;
onRowClick: (row: CsvRow) => void;
}
const a: ICsvReaderProps = {
headers: ['A', 'B', 'C'] as const,
onRowClick: (row) => console.log(row.Anything), // I want this to throw a type error since `Anything` !== `'A' | 'B' | 'C'`.
};
onRowClick
中的row
被推断为{ [x: string]: string }
,如何修改才能将x
推断为CsvHeaders
的元素?我不知道我哪里出错了,难道这在TS中还不可能吗?提前感谢!
1条答案
按热度按时间6rqinv9w1#
为了使其正常工作,在与
headers
属性的元素相对应的字符串文本类型的并集中,ICsvReaderProps
必须是generic:让我们调用类型参数T
:那么
onRowClick
回调的row
参数的类型为Record<T, string>
(使用Record<K, V>
实用程序类型来表示具有类型K
键和类型V
值的对象类型)。因此,示例对象的类型为
ICsvReaderProps<"A" | "B" | "C">
,为了避免手动指定该类型参数(这将使您编写"A"
、"B"
和"C"
两次),我们可以定义一个通用标识辅助函数:然后把
const a: ICsvReaderProps = {...};
写成const a = asCsvReaderProps({...});
,我们试试看:看起来不错。编译器根据
headers
属性推断T
是"A" | "B" | "C"
,因此在onRowClick
回调中上下文类型row
为Record<"A" | "B" | "C", string>
。因此row
已知具有A
、B
、和string
类型的C
属性。它不知道是否具有Anything
属性,因此根据需要出现编译器错误。Playground代码链接