Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Correctly generate types for Record<string, T> #1456

Merged
merged 3 commits into from
Aug 15, 2023

Conversation

ryanisaacg
Copy link
Contributor

@ryanisaacg ryanisaacg commented Jul 27, 2023

When encountering a Record whose key is string, tsoa would previously generate a blank object. This change allows the type resolver to recognize the record and generate its value type properly.

I would love guidance on where to add some tests for this PR! The test suite is a little opaque to me.

All Submissions:

  • Have you followed the guidelines in our Contributing document?
  • Have you checked to ensure there aren't other open Pull Requests for the same update/change?
  • Have you written unit tests?
  • Have you written unit tests that cover the negative cases (i.e.: if bad data is submitted, does the library respond properly)?
  • This PR is associated with an existing issue?

Closing issues

Closes #1407

If this is a new feature submission:

  • Has the issue had a maintainer respond to the issue and clarify that the feature is something that aligns with the goals and philosophy of the project?

Potential Problems With The Approach

Test plan

When encountering a Record whose key is string, tsoa would previously
generate a blank object. This change allows the type resolver to
recognize the record and generate its value type properly.

Intended to fix lukeautry#1407
Copy link

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hello there ryanisaacg 👋

Thank you and congrats 🎉 for opening your first PR on this project.✨

We will review the following PR soon! 👀

@WoH
Copy link
Collaborator

WoH commented Jul 28, 2023

@@ -420,6 +420,20 @@ export class TypeResolver {
return stringMetaType;
}

if (typeReference.typeName.text === 'Record' && typeReference.typeArguments?.length === 2) {
const indexType = new TypeResolver(typeReference.typeArguments[0], this.current, this.parentNode, this.context).resolve();
if (indexType.dataType === 'string') {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why only for string? We should be able to handle numbers, boolean, string enums, number enums etc.?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks for the number callout! I've added support here for numbers and test cases to verify

  • number enums and string enums are handled separately (I'm not sure where, but as you can see from the test suite they are handled correctly). They actually produce fairly different OpenAPI results, because of the way swagger handles dictionaries
  • boolean is not a valid Record key type; the type for Record's key is string | number | symbol. symbol isn't supported by tsoa it seems (which makes sense, because it doesn't belong in a public-facing API)

if (typeReference.typeName.text === 'Record' && typeReference.typeArguments?.length === 2) {
const indexType = new TypeResolver(typeReference.typeArguments[0], this.current, this.parentNode, this.context).resolve();
if (indexType.dataType === 'string') {
const valueType = new TypeResolver(typeReference.typeArguments[1], this.current, this.parentNode, this.context).resolve();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In case we are passing from parent (GenericModel has items: Record<string, T>) can you handle these without amending the context? (IIRC that should be created on processing the GenericModel<T>, but it would also be a good test probably.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How would I go about doing that? Should I be creating a new temporary context?

I'm not familiar with the codebase so I'm not sure what the context is here, or what purpose it serves, so I just followed the structure of other cases in this method.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be handled for you at this point already.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I'm not sure what you mean.

- Rename the existing 'record' test into 'stringUnionRecord' to
  distinguish it from the new test cases
- Add a 'numberUnionRecord' test case, which tests the same path
  as 'stringUnionRecord'
- Add two new cases, 'stringRecord' and 'numberRecord', which test
  Record<string, T> and Record<number, T>
@ryanisaacg
Copy link
Contributor Author

Thanks for the pointers! I've now added tests to cover my changes.

@WoH WoH merged commit 4f452f9 into lukeautry:master Aug 15, 2023
27 checks passed
@ryanisaacg ryanisaacg deleted the add-record-syntax-support branch August 22, 2023 21:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

How to represent Records
2 participants