如何在TypeScript中使用泛型编写可复用的TSV解析器?
解决TSV解析函数的类型标注问题
核心问题分析
你遇到的错误是因为TypeScript无法推断columns[j]是泛型T的合法键,同时泛型T没有被约束为对象类型,导致索引操作时类型不匹配。
修正方案
- 约束泛型T的类型:明确
T是键为字符串的对象类型,确保我们可以用字符串列名去索引它。 - 关联列名与T的键:将解析出的列名数组断言为
(keyof T)[](需要调用者保证TSV列名与T的键完全匹配,TypeScript无法在运行时验证这一点)。 - 修正循环起始索引:原代码从
i=2开始会跳过第一行数据(索引1),应该从i=1开始。
修改后的代码
import fs from 'fs'; export const parseTsv = <T extends Record<string, unknown>>(tsvFilepath: string): T[] => { const tsv = fs.readFileSync(tsvFilepath, 'utf8'); const lines = tsv.split('\n').filter(line => line.trim() !== ''); // 过滤空行 const result: T[] = []; if (lines.length === 0) return result; // 处理空文件情况 const columns = lines[0].split('\t') as (keyof T)[]; // 断言列名为T的键类型 for (let i = 1; i < lines.length; i++) { // 从索引1开始,跳过列名行 const obj = {} as T; const currentLine = lines[i].split('\t'); for (let j = 0; j < columns.length; j++) { if (j < currentLine.length) { // 避免列数不匹配导致的undefined赋值 obj[columns[j]] = currentLine[j]; } } result.push(obj); } return result; };
使用示例
定义你的数据接口,调用时传入泛型参数:
interface User { id: string; name: string; email: string; } const users = parseTsv<User>('./users.tsv'); // users的类型为User[]
额外说明
- 运行时无法自动验证TSV列名与
T的键是否一致,需要调用者确保文件结构和定义的接口匹配。 - 添加了空行过滤和列数检查,提升函数的健壮性,避免空行或列数不匹配导致的异常。
内容的提问来源于stack exchange,提问作者YSA
相关产品推荐
相关产品推荐

