简体   繁体   English

从 object 属性推断类型

[英]Infer type from object property

Is it possible to create a generic function that infers the type from the "external" object property?是否可以创建一个通用的 function 从“外部” object 属性推断类型?

Imagine something like this:想象一下这样的事情:

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);
  };
}

The goal would be so that the function returned by createResolver would match the exact return of "overallRankingPlacement" and the arguments passed to it would match just the same—kind of mirroring/proxying everything in regards to type.目标是使createResolver返回的 function 与“overallRankingPlacement”的确切返回匹配,并且传递给它的 arguments 将匹配相同的类型——镜像/代理所有关于类型的内容。

You can do this by using generic parameters for both the argument-array and the result type.您可以通过对参数数组和结果类型使用泛型参数来做到这一点。 Something like this will work:像这样的东西会起作用:

function createResolver<Args extends unknown[], Res>(
  resolverFn: (...args: Args) => Res
): (...args: Args) => Res {
  return (...args: Args) => {
    // Some additional logic...
    return resolverFn(...args);
  };
}

The resolversMap example above will still fail though, as the overallRankingPlacement function returns a promise, whereas the argument to createResolver doesn't.但是,上面的resolversMap示例仍然会失败,因为overallRankingPlacement返回 promise,而createResolver的参数不会。 You can fix it by removing Promise from the return type or passing an asynchronous function to createResolver to get the types in line.您可以通过从返回类型中删除Promise或将异步 function 传递给createResolver以获取符合要求的类型来修复它。

Maybe what you're looking for is a createResolver that returns an async function?也许您正在寻找的是一个返回异步 function 的createResolver If so, you could add a Promise and an async to the function above and get:如果是这样,您可以将Promiseasync添加到上面的 function 并获得:

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);
  };
}

This version will work correctly with your sample resolversMap .此版本将与您的示例resolversMap一起正常工作。

It may be worth noting that wrapping functions like this does not handle overloaded functions well.值得注意的是,像这样包装函数并不能很好地处理重载函数。 Only the last overload is retained, so for只有最后一个重载被保留,所以对于

function overloaded(x: number): number
function overloaded(x: string): string
function overloaded(x: number | string) {
    return x
}

the wrapped function will only be from string to string :包装的 function 只会从stringstring

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'.

I don't think there's any way around this yet, and maybe it won't even get supported at all.我认为目前还没有任何解决办法,甚至可能根本不会得到支持。

TypeScript playground TypeScript操场

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM