如何解构泛型以验证对象属性存在(支持嵌套且不约束T)?
实现支持属性访问的通用二分查找函数
核心需求拆解
- 兼容原始类型数组(直接用元素值查找)与对象数组(通过lambda提取属性,支持嵌套属性)
- 利用递归泛型约束属性访问路径,确保访问的属性必然存在于对象类型中
- 不扩展泛型
T的类型范围,保持输入类型的通用性 - 自动推导目标属性的类型
U,避免重复编写相似逻辑的重载函数
实现方案(TypeScript)
// 递归定义属性路径类型,确保访问的属性合法存在 type PropertyPath<T, U> = T extends U ? (item: T) => U : { [K in keyof T]: PropertyPath<T[K], U> extends infer F ? F extends (item: any) => U ? (item: T) => ReturnType<F> : never : never }[keyof T]; // 通用二分查找函数 function binarySearch<T, U>( arr: T[], target: U, getValue: PropertyPath<T, U> = (item: any) => item as U ): number { let left = 0; let right = arr.length - 1; while (left <= right) { const mid = Math.floor((left + right) / 2); const currentValue = getValue(arr[mid]); if (currentValue === target) { return mid; } else if (currentValue < (target as any)) { left = mid + 1; } else { right = mid - 1; } } return -1; }
使用示例
1. 原始类型数组查找
const nums = [2, 4, 6, 8, 10]; const numIndex = binarySearch(nums, 6); console.log(numIndex); // 输出: 2
2. 对象数组(单层属性)
interface Book { id: number; title: string; } const books: Book[] = [ { id: 1, title: "TypeScript实战" }, { id: 3, title: "前端工程化" }, { id: 5, title: "React设计模式" } ]; const bookIndex = binarySearch(books, 3, (book) => book.id); console.log(bookIndex); // 输出: 1
3. 对象数组(嵌套属性)
interface Author { name: string; contact: { email: string; }; } interface NestedBook { id: number; author: Author; } const nestedBooks: NestedBook[] = [ { id: 1, author: { name: "张三", contact: { email: "zhangsan@example.com" } } }, { id: 2, author: { name: "李四", contact: { email: "lisi@example.com" } } }, { id: 3, author: { name: "王五", contact: { email: "wangwu@example.com" } } } ]; const nestedIndex = binarySearch(nestedBooks, "lisi@example.com", (book) => book.author.contact.email); console.log(nestedIndex); // 输出: 1
关键细节说明
- 递归泛型
PropertyPath:自动校验lambda的属性访问路径,若访问不存在的属性,TypeScript会直接抛出类型错误,保证类型安全 - 默认属性提取器:当未传入第三个参数时,默认直接返回数组元素本身,完美适配原始类型数组的场景
- 无冗余重载:通过条件类型实现原始类型与对象类型的兼容,无需编写多个重载函数,保持函数的简洁性与通用性
内容的提问来源于stack exchange,提问作者jumbeldliam
相关产品推荐
相关产品推荐

