我想创建一个返回其通用类型参数功能的类型。它的行为应类似于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
的函数,但不是这样
编辑:我可能已经找到了解决方案,但是只有当我使用“ any”(通常没有不安全的any)时,我才找到解决方案。当提供的字段不是函数但不会引起任何编译错误时,这正确地推断出返回类型应为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;
}
答案 0 :(得分:0)
这是我的处理方法:
function toField<K extends keyof any>(key: K) {
return <T extends Record<K, () => any>>(value: T): ReturnType<T[K]> => value[key]();
}
在这里,toField()
是K
参数类型的key
中的泛型函数,它返回 T
中的泛型函数,即value
参数的类型。 T
限于类型具有键为K
的属性,该属性在该键处的值为零参数函数。 那个函数返回类型为ReturnType<T[K]>
的值,其中ReturnType<F>
为defined in the standard library是函数类型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()
中的contextual typing来推断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
推断任何内容,默认为{}
或unknown
,然后最终约束{{ 1}}到U
,并且never
无法分配给'getX'
。布莱但是在上面的代码中,在一行中调用或将其拆分为两行没有区别。
好的,希望能有所帮助。祝你好运!