Description
π Search Terms
"is referenced directly or indirectly in its own type annotation.ts(2502)"
"self-referencing types"
"circular types"
...
β Viability Checklist
- This wouldn't be a breaking change in existing TypeScript/JavaScript code
- This wouldn't change the runtime behavior of existing JavaScript code
- This could be implemented without emitting different JS based on the types of the expressions
- This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, new syntax sugar for JS, etc.)
- This isn't a request to add a new utility type: https://github.com/microsoft/TypeScript/wiki/No-New-Utility-Types
- This feature would agree with the rest of our Design Goals: https://github.com/Microsoft/TypeScript/wiki/TypeScript-Design-Goals
β 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);
}

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!