typescript - Typescript:返回给定类型函数的类型
问题描述
我想创建一个返回其泛型类型参数的函数的类型。它的行为应该像keyof
但只返回用于调用函数的键
我正在使用打字稿 3.4.5。
用例:
type FunctionOf<T> = ... // <-- what I want
function testFunction<T, U extends FunctionOf<T>>(obj: T, functionName: U): T[U] {
return obj[functionName]();
}
我的具体情况:
export type Mapper<T, U> = (value: T, index?: number, array?: T[]) => U;
type IsFunction<T> = T extends Function ? T & Function : never;
export function toField<T, U extends keyof T, V extends IsFunction<T[U]>>(key: U): Mapper<T, V extends () => infer R ? R : never> {
return (value: T) => (value[key] as V)();
}
class Test {
x: string;
constructor(x: string) {
this.x = x;
}
getX(): string { return this.x; }
}
const y: Test[] = [new Test('hello')];
y.map(toField('getX')); // putting in 'x' will not cause the entire return to be never which is what I want.
我希望以上内容将接受的参数限制为的功能,Test
但它没有
编辑:我可能已经找到了解决方案,但只有当我使用“任何”时(我通常没有不安全的任何)。这正确地推断出返回类型应该是never
当提供的字段不是函数时,但不会导致任何编译错误。虽然这解决了我的具体情况,但我仍然想找到一种更有效地输入它的方法
export type Mapper<T, U> = (value: T, index?: number, array?: T[]) => U;
type IsFunction<T> = T extends Function ? T & Function : never;
export function toField<T, U extends keyof T, V extends IsFunction<T[U]>>(
key: U
): V extends Function ? Mapper<T, V extends () => infer R ? R : never> : never {
return ((value: T) => (value[key] as V)()) as any;
}
解决方案
以下是我的处理方式:
function toField<K extends keyof any>(key: K) {
return <T extends Record<K, () => any>>(value: T): ReturnType<T[K]> => value[key]();
}
这里,toField()
是一个泛型函数 in K
,key
参数的类型,它返回一个泛型函数 in T
,value
参数的类型。 T
被限制为具有 key 属性的类型K
,其在该键处的属性值是一个零参数函数。 该函数返回一个类型的值ReturnType<T[K]>
,其中在标准库ReturnType<F>
中定义为函数类型的返回类型的类型。 F
让我们测试一下:
class Test {
x: string;
constructor(x: string) {
this.x = x;
}
getX(): string { return this.x; }
}
const y: Test[] = [new Test('hello')];
const strings = y.map(toField('getX')); // okay, string[]
const doesntWork = y.map(toField('x')); // error!
// ~~~~~~~~~~~~
// y.map() doesn't accept a toField('x'), since Test['x'] is not a zero arg fn
我认为最好y.map(toField('x'))
是编译时警告,而不是在编译时默默地产生类型值never[]
。你根本不想传递toField('x')
给y.map()
。
还有几个案例:
const thisWorks = toField('toLowerCase')("LOWERCASE");
const thisDoesnt = toField('charAt')("oops"); // error!
// ~~~~~~
// "oops".charAt is a function but needs args
你可以打电话"LOWERCASE".toLowerCase()
,但不应该不能打电话"oops".charAt()
。
最后,请注意,您的原始类型实际上只在一行中起作用,arr.map(toField("xxx"))
因为它依赖于上下文类型来arr.map()
推断toField()
. 你这样做会遇到麻烦:
const getXField = toField('getX');
// const getXField: <T extends Record<"getX", () => any>>(value: T) => ReturnType<T["getX"]>
const stringsTwoStep = y.map(getXField); // okay, string[]
对于您的原始代码,第一行将是一个错误,因为它无法推断出任何内容T
,默认为{}
or unknown
,然后最终限制U
为never
,并且'getX'
不可分配给never
。布莱。但是在上面的代码中,在一行中调用它或将它分成两行没有区别。
好的,希望有帮助。祝你好运!
推荐阅读
- javascript - Javascript 承诺链地狱
- r - 如何获得多变量逻辑回归模型(glm)的校准图?
- python - 套接字尝试连接异常
- google-apps-script - Gmail 自动回复脚本 - 如何设置条件时间并停止多个回复?
- docker - docker 卷中的文件未更新
- python - 当另一个选择小部件更改时,如何自动更新下拉选择小部件?(Python面板pyviz)
- css - 仅对 SVG 中的一条路径进行动画处理而不进行裁剪
- java - Wildfly 和 haproxy 之间的对话 - 无效的 PROXY 协议标头
- python - python-shapefile 将几何图形转换为纬度/经度
- java - 我怎样才能将一个名单平均分成 2 或 4 组并打印出来?