typescript - 如何正确缩小包含“对象键或函数”的函数参数
问题描述
我正在尝试创建一个通用类型“使用字符串键或回调获取属性”函数,并且我已经碰壁让 TS 将我的类型参数缩小到包含对象的键。
功能如下:
function get<T, V>(value: T, fn: (value: T) => V): V;
function get<T, P extends keyof T>(value: T, prop: P): T[P];
function get<T, P extends keyof T>(value: T, prop: P | ((value: T) => any)):
typeof prop extends (o: any) => infer V ? V : T[P] {
switch (typeof prop) {
case 'function':
return prop(value);
case 'string':
return value[prop]; // ERROR HERE
default: throw new TypeError('Property getter must be string or function');
}
}
并且编译器在string
分支中抱怨 - 显然prop
不是缩小到P
,而是缩小到P & string
,这不能在这里使用,因为它意味着试图返回需要T[string]
aT[P]
的地方。
有没有办法正确指定这个,或者我只是叹息并抑制错误?
解决方案
function get<T, V>(value: T, fn: (value: T) => V): V;
function get<T, P extends keyof T>(value: T, prop: P): T[P];
function get<T, P extends keyof T>(value: T, prop: P | ((value: T) => any)) {
if (typeof prop === 'function') {
return prop(value);
}
if (prop in value) {
return value[prop];
}
throw new TypeError('Property getter must be string or function');
}
const a = get(1, (a) => a + 1);
const b = get({a: 'a'}, 'a')
console.log(a); // 2
console.log(b);// "a"
解释。之前的实现有几个问题:
- 返回类型已在重载中定义,无需在实现中再次定义
- 检查 typeof 字符串会自动创建与
string
type的交集
解决方案是使用key in object
语法,这给了我们类型规范,V[P]
第二个分支正在检查typeof function
与字符串相交的确切问题是,原始实现无法使用所有可能的键类型,即 - number | string | symbol
。对于除字符串以外的任何键,该函数将抛出异常。考虑下面的例子:
// symbol prop example
const symbolProp = Symbol()
const v = get({[prop]: 'value'}, prop);
// array example
const v2 = get([1, 2], 1);
// object with number key example
const v3 = get({1: 'value'}, 1);
所有三个示例都将是类型正确的,但会引发错误,因为 key 不是字符串。对于我提出的解决方案,它们都将正常工作。关键区别在于prop in value
它确保 prop 是值键,但不需要特定类型的键。
如果我们真的想确保我们只需要字符串键,那么函数类型定义应该反映这一点。考虑:
function get<T, V>(value: T, fn: (value: T) => V): V;
function get<T, P extends keyof T & string>(value: T, prop: P): T[P];
function get<T, P extends keyof T & string>(value: T, prop: P | ((value: T) => any)) {
switch (typeof prop) {
case 'function':
return prop(value);
case 'string':
return value[prop];
default: throw new TypeError('Property getter must be string or function');
}
}
核心区别是 -P extends keyof T & string
我们在类型级别上说我们只接受 P 的键,它们也是字符串。这种方法与我们检查的实现是一致的typeof string
。
推荐阅读
- python - 如何锁定默认选项而不在 DJANGO 中提供任何选项
- java - 重新访问数据库时文件内容不正确
- python - 从 ReacJS 前端到 python FastAPI 应用程序的 CORS 块请求
- mongodb - 项目中的 MongoDB 计数条件与 $eq
- kubernetes - 如何避免对属于 K8s 服务的 pod 的并行请求?
- java - 如何在 Java 中将字节转换为兆位?
- python - Python:使用字符串调用子函数
- javascript - 使用服务工作者在 IndexedDB 中创建存储的困难
- elasticsearch - Elasticsearch 文档搜索相关
- batch-file - 如何将bat转为exe并让exe接收参数?