TypeScript中如何通过typeof实现类型窄化?解决特定类型函数调用报错
解决TypeScript中联合类型属性排序时的类型守卫失效问题
你的问题核心在于:sortBy是"sortFoo" | "sortBar"的联合类型,TypeScript无法在回调函数中将typeof arg[sortBy]的运行时检查与sortBy的具体值关联起来,导致arg[sortBy]始终被推断为string | number,因此调用toLowerCase()会触发类型错误。
解决方案:用泛型绑定属性键的具体类型
将排序函数改造成接收sortBy参数的泛型函数,让TypeScript能根据传入的属性键,精确推断出对应属性的类型,此时typeof类型守卫就能正常工作:
interface ObjectProps { sortFoo: string, sortBar: number } const getSortKey = (): "sortFoo" | "sortBar" => { // 示例实现 return Math.random() > 0.5 ? "sortFoo" : "sortBar"; }; const getArrayOfObjects = (): ObjectProps[] => { // 示例实现 return [ { sortFoo: "Apple", sortBar: 3 }, { sortFoo: "banana", sortBar: 1 }, { sortFoo: "Cherry", sortBar: 2 } ]; }; // 泛型排序函数,K绑定具体的属性键类型 const sortList = <K extends keyof ObjectProps>(sortBy: K) => { return (a: ObjectProps, b: ObjectProps): number => { const valA = a[sortBy]; const valB = b[sortBy]; // 针对字符串类型做小写转换后比较 if (typeof valA === "string" && typeof valB === "string") { return valA.toLowerCase().localeCompare(valB.toLowerCase()); } // 针对数字类型直接比较 if (typeof valA === "number" && typeof valB === "number") { return valA - valB; } // 处理混合类型的边界情况(根据需求调整) return 0; }; }; const sortBy: "sortFoo" | "sortBar" = getSortKey(); const objects: ObjectProps[] = getArrayOfObjects().sort(sortList(sortBy));
为什么原来的写法不行?
在你最初的代码中,sortBy是联合类型,TypeScript无法在map回调里推断出:当typeof arg[sortBy] === 'string'时,sortBy一定是"sortFoo"(对应字符串属性)。因此arg[sortBy]的类型始终是string | number,TypeScript不允许你在可能为数字的值上调用toLowerCase()。
备选方案:类型断言(不推荐)
如果你不想重构函数,也可以用类型断言跳过TypeScript的检查,但这种方法不安全(如果后续属性类型或sortBy的范围变化,容易引入bug):
const sortList = (...args: ObjectProps[]): number => { const compare: (string | number)[] = args.map( (arg: ObjectProps): string | number => typeof arg[sortBy] === 'string' ? (arg[sortBy] as string).toLowerCase() : arg[sortBy] ); return compare[0] < compare[1] ? -1 : 1; };
内容的提问来源于stack exchange,提问作者colin
相关产品推荐
相关产品推荐

