从对象推断类型 属性
Infer type from object property
是否可以创建一个从“外部”对象推断类型的通用函数属性?
想象一下这样的事情:
const resolversMap: {
overallRankingPlacement: (issuer: number, args: Record<string, any>, context: Record<string, any>) => Promise<number>;
} = {
overallRankingPlacement: createResolver((issuer, args, context) => {
return 0;
}),
};
function createResolver<T extends () => void>(resolverFn: T): ReturnType<T> {
return (...args) => {
// Some additional logic...
resolverFn(...args);
};
}
目标是让 createResolver
编辑的函数 return 与“overallRankingPlacement”的 return 完全匹配,并且传递给它的参数也将完全匹配—— mirroring/proxying 关于类型的一切。
您可以通过对参数数组和结果类型使用通用参数来实现。这样的事情会起作用:
function createResolver<Args extends unknown[], Res>(
resolverFn: (...args: Args) => Res
): (...args: Args) => Res {
return (...args: Args) => {
// Some additional logic...
return resolverFn(...args);
};
}
上面的 resolversMap
示例仍然会失败,因为 overallRankingPlacement
函数 return 是一个承诺,而 createResolver
的参数不是。您可以通过从 return 类型中删除 Promise
或将异步函数传递给 createResolver
以获取行中的类型来修复它。
也许您正在寻找的是 createResolver
并且 return 是一个异步函数?如果是这样,您可以在上面的函数中添加一个 Promise
和一个 async
并得到:
function createAsyncResolver<Args extends unknown[], Res>(
resolverFn: (...args: Args) => Res
): (...args: Args) => Promise<Res> {
return async (...args: Args) => {
// Some additional async logic...
return resolverFn(...args);
};
}
此版本将与您的示例一起正常工作 resolversMap
。
可能值得注意的是,像这样包装函数并不能很好地处理重载函数。只保留最后一次重载,所以for
function overloaded(x: number): number
function overloaded(x: string): string
function overloaded(x: number | string) {
return x
}
包装函数只会从string
到string
:
const unfortunatelyNotOverloaded = createResolver(overloaded)
const ok = unfortunatelyNotOverloaded('ok') // inferred type: string
const fail = unfortunatelyNotOverloaded(1)
// ERROR: Argument of type 'number' is not assignable to parameter of type 'string'.
我认为目前还没有解决这个问题的办法,也许它根本不会得到支持。
是否可以创建一个从“外部”对象推断类型的通用函数属性?
想象一下这样的事情:
const resolversMap: {
overallRankingPlacement: (issuer: number, args: Record<string, any>, context: Record<string, any>) => Promise<number>;
} = {
overallRankingPlacement: createResolver((issuer, args, context) => {
return 0;
}),
};
function createResolver<T extends () => void>(resolverFn: T): ReturnType<T> {
return (...args) => {
// Some additional logic...
resolverFn(...args);
};
}
目标是让 createResolver
编辑的函数 return 与“overallRankingPlacement”的 return 完全匹配,并且传递给它的参数也将完全匹配—— mirroring/proxying 关于类型的一切。
您可以通过对参数数组和结果类型使用通用参数来实现。这样的事情会起作用:
function createResolver<Args extends unknown[], Res>(
resolverFn: (...args: Args) => Res
): (...args: Args) => Res {
return (...args: Args) => {
// Some additional logic...
return resolverFn(...args);
};
}
上面的 resolversMap
示例仍然会失败,因为 overallRankingPlacement
函数 return 是一个承诺,而 createResolver
的参数不是。您可以通过从 return 类型中删除 Promise
或将异步函数传递给 createResolver
以获取行中的类型来修复它。
也许您正在寻找的是 createResolver
并且 return 是一个异步函数?如果是这样,您可以在上面的函数中添加一个 Promise
和一个 async
并得到:
function createAsyncResolver<Args extends unknown[], Res>(
resolverFn: (...args: Args) => Res
): (...args: Args) => Promise<Res> {
return async (...args: Args) => {
// Some additional async logic...
return resolverFn(...args);
};
}
此版本将与您的示例一起正常工作 resolversMap
。
可能值得注意的是,像这样包装函数并不能很好地处理重载函数。只保留最后一次重载,所以for
function overloaded(x: number): number
function overloaded(x: string): string
function overloaded(x: number | string) {
return x
}
包装函数只会从string
到string
:
const unfortunatelyNotOverloaded = createResolver(overloaded)
const ok = unfortunatelyNotOverloaded('ok') // inferred type: string
const fail = unfortunatelyNotOverloaded(1)
// ERROR: Argument of type 'number' is not assignable to parameter of type 'string'.
我认为目前还没有解决这个问题的办法,也许它根本不会得到支持。