如何在TypeScript泛型中校验指定键对应值的类型?
问题:如何在TypeScript中校验泛型对象指定键的值类型?
我写了一个sortData函数,用来接收键名并根据该键对应的值对对象数组排序:
function compare(v1: string | number, v2: string | number) { return (v1 < v2 ? -1 : v1 > v2 ? 1 : 0); } function sortData<T>(data: Array<T>, column: keyof T, direction: string): Array<T> { if (direction === '' || column === '') { return data; } else { return [...data].sort((a, b) => { const res = compare(a[column], b[column]); return direction === 'asc' ? res : -res; }); } }
现在的问题是,泛型T的对象中,column指定的键对应的值类型可能不是string | number,没法合法传入compare函数。我希望调用sortData时,如果传入的column对应值类型不符合要求,TypeScript编译器直接报错。请问该怎么校验泛型对象指定键的值类型?
解决方案
要实现这个校验,核心是给泛型和参数加类型约束,确保传入的column对应的属性值必须是string | number。下面两种方法都能解决问题:
方法1:筛选对象中可排序的键(推荐)
先定义一个工具类型,提取出对象中值类型为string | number的键,然后让column参数只能是这些键:
function compare(v1: string | number, v2: string | number) { return (v1 < v2 ? -1 : v1 > v2 ? 1 : 0); } // 工具类型:提取T中值类型为string | number的键 type ValidSortKey<T> = { [K in keyof T]: T[K] extends string | number ? K : never; }[keyof T]; function sortData<T>( data: T[], column: ValidSortKey<T>, direction: 'asc' | 'desc' | '' = '' // 把direction改成字面量类型,避免传入无效字符串 ): T[] { if (!direction || !column) { return data; } return [...data].sort((a, b) => { const res = compare(a[column], b[column]); return direction === 'asc' ? res : -res; }); }
方法2:直接约束整个对象的属性类型
如果你的场景里,传入的数组对象所有属性都必须是可排序的(即值为string | number),可以直接给泛型T加约束:
function compare(v1: string | number, v2: string | number) { return (v1 < v2 ? -1 : v1 > v2 ? 1 : 0); } // 约束T的所有属性值都是string或number function sortData<T extends Record<string, string | number>>( data: T[], column: keyof T, direction: 'asc' | 'desc' | '' = '' ): T[] { if (!direction || !column) { return data; } return [...data].sort((a, b) => { const res = compare(a[column], b[column]); return direction === 'asc' ? res : -res; }); }
效果验证
现在当你传入不符合要求的column时,TypeScript会立刻报错:
interface User { name: string; age: number; isActive: boolean; // 这个属性值是boolean,不能用于排序 } const users: User[] = [ { name: 'Alice', age: 25, isActive: true }, { name: 'Bob', age: 30, isActive: false } ]; sortData(users, 'isActive', 'asc'); // 编译器报错:"isActive"不能赋值给ValidSortKey<User>类型的参数
内容的提问来源于stack exchange,提问作者Him
相关产品推荐
相关产品推荐

