能否通过泛型实现函数遇undefined时返回指定错误文本(无需try catch与默认值)
解决方案
当然可以实现,不用try/catch或默认值,结合泛型和逐段路径校验就能搞定。先说说你原代码里的几个问题:
- 泛型参数和全局
returnType类型重名,容易混淆报错 - 用
forEach遍历路径没法中途中断,而且一旦中间值变成undefined,后续访问属性会直接报错 - 完全没处理值为
undefined的场景,直接用类型断言会导致类型不安全
下面是优化后的实现:
// 泛型T表示错误文本的类型,返回值为路径对应的属性类型 | T function getValue<T>(path: string, obj: Record<string, unknown>, errorText: T): unknown | T { let currentValue: unknown = obj; const pathSegments = path.split('.'); for (const segment of pathSegments) { // 每一步都检查当前值是否是可索引的对象/数组,并且包含当前路径段 if (typeof currentValue === 'object' && currentValue !== null && segment in (currentValue as Record<string, unknown>)) { currentValue = (currentValue as Record<string, unknown>)[segment]; } else { // 路径不存在,直接返回错误文本 return errorText; } } // 遍历完路径后,检查最终值是否为undefined,是就返回错误文本 return currentValue === undefined ? errorText : currentValue; } // 测试示例 const stroka: string = 'a.b.c'; const alerts: string = 'asd'; console.log(getValue(stroka, {a: {b:{f: 3}}}, alerts)); // 输出: 'asd' console.log(getValue('a.b.f', {a: {b:{f: 3}}}, alerts)); // 输出: 3
关键细节:
- 泛型T:用来约束错误文本的类型,让函数支持返回不同类型的错误信息(比如字符串、数字都可以)
- 逐段校验:用
for...of循环代替forEach,每一步都做合法性检查,避免访问undefined的属性报错,还能中途返回错误文本 - undefined处理:遍历结束后额外判断最终值是否为undefined,完全符合你的需求
- 类型约束:用
Record<string, unknown>代替object类型,解决了原代码里对象无法索引的问题
如果想要更精确的类型推断(让TS自动识别路径对应的属性类型),可以再加个类型工具函数:
// 递归解析路径对应的属性类型 type PathValue<T, P extends string> = P extends `${infer K}.${infer Rest}` ? K extends keyof T ? PathValue<T[K], Rest> : never : P extends keyof T ? T[P] : never; function getValue<O extends Record<string, unknown>, P extends string, T>( path: P, obj: O, errorText: T ): PathValue<O, P> | T { let currentValue: unknown = obj; const pathSegments = path.split('.'); for (const segment of pathSegments) { if (typeof currentValue === 'object' && currentValue !== null && segment in (currentValue as Record<string, unknown>)) { currentValue = (currentValue as Record<string, unknown>)[segment]; } else { return errorText as T; } } return (currentValue === undefined ? errorText : currentValue) as PathValue<O, P> | T; } // 测试时类型会自动推导 const testObj = {a: {b:{f: 3}}}; const result1 = getValue('a.b.f', testObj, 'asd'); // 类型为number | string const result2 = getValue('a.b.c', testObj, 'asd'); // 类型为number | string,实际返回'asd'
这个版本能让TS自动推断出返回值的类型是路径属性类型或错误文本类型,类型安全性更高。
内容的提问来源于stack exchange,提问作者Владислав Куликов
相关产品推荐
相关产品推荐

