tsoa
tsoa copied to clipboard
Recursive generic types infinitely recurse when generating routes
Sorting
-
I'm submitting a ...
- [X] bug report
- [ ] feature request
- [ ] support request
-
I confirm that I
- [X] used the search to make sure that a similar issue hasn't already been submit
Steps to repro
- Create a controller class file with the following contents
import { Get } from "api-external/src/rest/decorators/methods";
import { Controller, Route } from "tsoa";
/**
* If T is an object, it returns T with an additional ID property
* Otherwise we just return T
*/
type WithIdForObjectTypes<T> = T extends Record<string, any>
? AddIdToSubObjects<T> & { id: number }
: T;
/**
* This remaps a key-value mapping such that any object value has an additional ID property.
* This is mutually recursive with WithIdForObjectTypes so that deeply nested objects also get the additional ID property.
* e.g. { topLevelField: { subField: string } } -> { topLevelField: { subField: string, id: number } }
*
*/
type AddIdToSubObjects<T extends Record<string, any>> = {
[K in keyof T]: WithIdForObjectTypes<T[K]>;
};
/** Example case */
type MyObject = AddIdToSubObjects<{ topLevelField: { subField: string } }>;
@Route("example")
export class ExampleController extends Controller {
@Get("example-endpoint")
public async get() {
const myObject: MyObject = {
topLevelField: {
subField: "foo",
id: 1,
},
};
return {
myObject,
};
}
}
- Run
tsoa routes
Expected Behavior
I would expect this type to correctly resolve when running the tsoa cli (tsoa spec-and-routes
).
Specifically, the endpoint GET /example/example-endpoint should have a response type of
{
topLevelField: {
subField: string,
id: number
}
}
Current Behavior
The tsoa cli is erroring out with the following error.
/** MANY MORE SIMILAR LOG LINES OMITTED FOR BREVITY **/
There was a problem resolving type of 'WithIdForObjectTypes<{"topLevelField": {"subField": string}}[string][string][string][string]>'.
There was a problem resolving type of 'WithIdForObjectTypes<{"topLevelField": {"subField": string}}[string][string][string]>'.
There was a problem resolving type of 'WithIdForObjectTypes<{"topLevelField": {"subField": string}}[string][string]>'.
There was a problem resolving type of 'WithIdForObjectTypes<{"topLevelField": {"subField": string}}[string]>'.
There was a problem resolving type of 'AddIdToSubObjects<{"topLevelField": {"subField": string}}>'.
Generate routes error.
RangeError: Maximum call stack size exceeded
at writeOrBuffer (node:internal/streams/writable:553:21)
at _write (node:internal/streams/writable:490:10)
at Writable.write (node:internal/streams/writable:494:10)
at console.value (node:internal/console/constructor:304:16)
at console.warn (node:internal/console/constructor:384:26)
at calcReferenceType (/workspaces/obsidian/node_modules/@tsoa/cli/dist/metadataGeneration/typeResolver.js:929:25)
at TypeResolver.getReferenceType (/workspaces/obsidian/node_modules/@tsoa/cli/dist/metadataGeneration/typeResolver.js:933:24)
at TypeResolver.resolve (/workspaces/obsidian/node_modules/@tsoa/cli/dist/metadataGeneration/typeResolver.js:513:36)
at TypeResolver.resolve (/workspaces/obsidian/node_modules/@tsoa/cli/dist/metadataGeneration/typeResolver.js:303:106)
at TypeResolver.getTypeAliasReference (/workspaces/obsidian/node_modules/@tsoa/cli/dist/metadataGeneration/typeResolver.js:1019:126)
It seems like it's infinitely recursing when trying to resolve the given type.
Context (Environment)
Version of the library: 6.0.1 (also tried with 6.0.0) Version of NodeJS: 20.10.0
- Confirm you were using yarn not npm: [x]
Hello there jancastor 👋
Thank you for opening your very first issue in this project.
We will try to get back to you as soon as we can.👀