lukeautry / tsoa

Build OpenAPI-compliant REST APIs using TypeScript and Node
MIT License
3.42k stars 489 forks source link

Nullable information is lost with Typescript Utility Type (Pick, Partial, ...) #1515

Open bigen1925 opened 9 months ago

bigen1925 commented 9 months ago

Sorting

Expected Behavior

{
    "schemas": {
      "Partial__nullableString-string-or-null__": {
        "properties": {
          "nullableString": {
            "type": "string",
            "nullable": true  #### nullable should be included
          }
        },
        "type": "object",
        "description": "Make all properties in T optional"
      },
      "ReturnType": {
        "$ref": "#/components/schemas/Partial__nullableString-string-or-null__"
      }
    },
}

Current Behavior

{
    "schemas": {
      "Partial__nullableString-string-or-null__": {
        "properties": {
          "nullableString": {
            "type": "string"  #### nullable is not included
          }
        },
        "type": "object",
        "description": "Make all properties in T optional"
      },
      "ReturnType": {
        "$ref": "#/components/schemas/Partial__nullableString-string-or-null__"
      }
    },
}

Possible Solution

make nullable information not to be lost

Steps to Reproduce

  1. with Controller
    
    import { Controller, Get, Route } from "tsoa";

type ReturnType = Partial<{ nullableString: string | null }>;

@Route("sample") export class SampleController extends Controller { @Get() getSample(): ReturnType { return {} as any; } }



2. `npx tsoa spec`

## Context (Environment)

Version of the library: tsoa@6.0.0-rc.5
Version of NodeJS: v18.15.0

- Confirm you were using yarn not npm: [x]

## Detailed Description
Thank you in advance for your development and maintenance for this awesome framework!
I love and use in production this :)

I confirmed that `nullable` is lost when defining types with `Pick` and `Partial` and `Exclude`.

This didn't happen (`nullable` is NOT lost) in `tsoa@5.1.1`.

Please let me know if I can provide any more information.

## Breaking change?

NO
gcv-epalmer commented 8 months ago

I have also ran into this issue! I upgraded from 5.1.1 to this 6.0.0-rc.5 in order to fix this issue with Omit and PIck: https://github.com/lukeautry/tsoa/issues/1238, and now am losing the nullable in the generated swagger

gcv-epalmer commented 8 months ago

I created a failing unit test for this: https://github.com/gcv-epalmer/tsoa-test

Tried my hand at fixing the bug but I think I'm a bit over my head. My best guess is that the TypeResolver doesn't play super nicely with reference/mapped types

mch-outsight commented 7 months ago

I also encountered this issue while bumping tsoa from 5.1.1 to 6.0.0, I confirm that I lost the nullable attribute while using Partial alias in TypeScript:

export default interface UserInsertionBody {
    username: string
    password: string
    roles?: { roleName: ROLE_NAME; siteId: string | null }[]
    preferences?: UserPreferences | null
}

I lose nullable in both roles.siteId and preferences attributes when using Partial<UserInsertionBody>. Thank you @bigen1925 and @gcv-epalmer for pointing it out!

iffa commented 6 months ago

Encountered this as well, attempted to fix it by taking a 4 hour deep dive into this library's internals & typescript AST, and noted the fact that if you enable strictNullChecks in tsoa's compilerOptions, this stats working again.

Noteworthy however is that with strictNullChecks enabled, some of tsoa's test suite fails, when I tested just applying that by default in the library itself.

PavelSarlov commented 4 months ago

Are there any updates on this? I'd like to get rid of the any types I am forced to use across the app because the validators won't allow nullables of any type.

JoranLive commented 2 months ago

Up.

Issue with body validation and Partial as described here: https://github.com/lukeautry/tsoa/issues/1612

Fixed thanks to @iffa with strictNullChecks

vedtam commented 1 month ago

@JoranLive, could you explain how is this fixed? I'm having the same issue. I define a property like:

titleTag?: string | null;

But when passing null to it, TSOA throws:

'locations.$0.titleTag': { message: 'invalid string value', value: null }

Thanks!

dsambugaro commented 1 month ago

@vedtam , the workaround is adding "strictNullChecks": true under compilerOptions at tsoa config file

vedtam commented 1 month ago

@dsambugaro thanks, but compilerOptions aren't taken from tsconfig.json? I have the flag "strictNullChecks" set there, and been having the issue still.

dsambugaro commented 1 month ago

@vedtam the tsoa.json also accepts the compilerOptions. I'm unsure if tsoa takes compilerOptions from tsconfig.json, or if it has some bug on this behavior since it was only "fixed" when I explicitly set it on tsoa.json. It is working for me until now

{
  "spec": {
    ...
  },
  "routes": {
    ...
  },
   "compilerOptions": {
        "strictNullChecks": true,
    }
}
vedtam commented 1 month ago

@dsambugaro got it, thanks!