Skip to content

Only resolve source return type when actually needed during inference when generic is usedΒ #58926

Closed
@finom

Description

@finom

πŸ” Search Terms

"is referenced directly or indirectly in its own type annotation.ts(2502)"
"self-referencing types"
"circular types"
...

βœ… Viability Checklist

⭐ Suggestion

Thanks to @ahejlsberg the issue #58616 was solved and the change works perfectly. Unfortunately my last comment was written too late and got lost among the other comments and issues. The code like this now works:

function foo(arg: Parameters<typeof bar>[0]) {
  return arg;
}

function bar(arg: string) {
  return foo(arg);
}

But in case if generics are used the arg wouldn't be recognised as expected, even if we still don't need to infer the return type.

πŸ“ƒ Motivating Example

function withCallback<T, R>(arg: T, handler: (arg2: T) => R) {
  console.log(arg);
  return handler;
}

const foo = withCallback('hello', (arg) => {
  return bar(arg);
});

function bar(arg: Parameters<typeof foo>[0]) {
   console.log(arg);
}
image

As you can see the requirement is very similar: we don't need to infer the function type fully, we just need to get the parameters type, and at this example the only argument should clearly be inferred as a string.

πŸ’» Use Cases

I work on a back-end library that relies on service-controller-repository pattern. The idea is to return service method call result from a controller, and to make the service method to accept parameters that are inferred from parameters of the controller.

class X {
  static foo = withCallback('hello', (arg) => {
    return Y.bar(arg);
  });
}

class Y {
  static bar(arg: Parameters<typeof X.foo>[0]) {
    console.log(arg);
  }
}

There is what I actually trying to achieve, it's a bit more complex than the previous examples:

class Service {
  static doSomething(body: VovkControllerBody<typeof Controller.doSomething>) {
    console.log(body);
  }
}

class Controller {
  static doSomething = withZod(z.object({ a: z.string() }), null, async (req) => {
    const body = await req.json(); // body has type of { a: string }
    return Service.doSomething(body); 
  });
}

VovkControllerBody infers the JSON body from Controller.doSomething argument defined by withZod.

The only workaround here is to have Zod schemas somewhere outside of the classes. But it requires to define extra variables and imports making the code less readable in large apps.

Thanks!

Metadata

Metadata

Assignees

Labels

Needs InvestigationThis issue needs a team member to investigate its status.SuggestionAn idea for TypeScript

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions