tsoa icon indicating copy to clipboard operation
tsoa copied to clipboard

Record<string, unknown> does not allow additional properties

Open yannbriancon opened this issue 3 years ago • 4 comments
trafficstars

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

Expected Behavior

A body with a field attributes: Record<string, unknown> and should allow additional properties even with "noImplicitAdditionalProperties": "throw-on-extras", in tsoa.json.

Current Behavior

A body with a field attributes: Record<string, unknown> with "noImplicitAdditionalProperties": "throw-on-extras", in tsoa.json triggers a validation error:

{"requestBody.attributes":{"message":"\"test\" is an excess property and therefore is not allowed","value":{"test":"test"}}}

Possible Solution

Steps to Reproduce

  1. Add an interface interface GeometryPostBody { attributes?: Record<string | number, unknown> }
  2. Set the interface as the expected body of a POST request
  3. Try to POST with the body {"attributes": {"test": "test"}}
  4. Receive a validation error {"requestBody.attributes":{"message":"\"test\" is an excess property and therefore is not allowed","value":{"test":"test"}}}

Context (Environment)

Version of the library: 3.14.1 Version of NodeJS: v16.13.1

  • Confirm you were using yarn not npm: [ ]

Detailed Description

Breaking change?

yannbriancon avatar Mar 02 '22 13:03 yannbriancon

Hello there yannbriancon 👋

Thank you for opening your very first issue in this project.

We will try to get back to you as soon as we can.👀

github-actions[bot] avatar Mar 02 '22 13:03 github-actions[bot]

Hello all!

If it can help, I found a workaround by replacing Record<string, unknown> by { [key: string]: unknown }.

It would still be great to find how to fix the real issue with Record 😉

The swagger.json is very different in each case:

  • With Record<string, unknown>:
...
"Record_string.unknown_": {
    "properties": {},
    "type": "object",
    "description": "Construct a type with a set of properties K of type T"
},
"Dto": {
  "properties": {
      "attributes": {
        "allOf": [
	        {
		        "$ref": "#/components/schemas/Record_string.unknown_"
	        }
        ]
      }
  },
  "type": "object",
}
...
  • With { [key: string]: unknown }:
...
"Dto": {
  "properties": {
    "attributes": {
        "properties": {},
        "additionalProperties": {},
        "type": "object"
    }
  },
  "type": "object",
}
...

yannbriancon avatar Mar 03 '22 09:03 yannbriancon

I also ran into this issue. I was hoping to do something like

type Foo = string;
Record<Foo, number>

But not only does this not work, { [key: Foo]: number} doesn't work either and instead fails with Error: Only string indexers are supported. This is unfortunate since I was hoping to split Foo as a separate type so that I can proper give it decorators.

SebastienGllmt avatar May 20 '22 19:05 SebastienGllmt

@SebastienGllmt I've had the same problem as you. I want to accept a body of type Record<UUID, {data: string, signature: string}> where type UUID = string.

@yannbriancon's { [key: string]: unknown } trick works for this and I think it will work for you too. I can choose the type to be {[key: string]: {data: string, signature: string}} for TSOA. This type even is compatible with Record<UUID, {data: string, signature: string}> that I then can use in the rest of my application without casting.

m1cm1c avatar Aug 09 '22 08:08 m1cm1c

I have a related question based on the above. According the Swagger definition for "Free-form object": https://swagger.io/docs/specification/data-models/data-types/#object, the following specifications are equivalent representations:

type: object
type: object
additionalProperties: true
type: object
additionalProperties: {}

However, using the type { [key: string]: unknown } becomes:

type: object
properties: {}
additionalProperties: {}

The additional properties field is messing with an auto-generated API documentation tool that I'm using. Does anyone know how to remove this properties field using tsoa? I can always do it manually, but was hoping to be able to generate the Swagger and feed it into the documentation tool automatically. Thanks!

stevenwchien avatar Nov 21 '23 18:11 stevenwchien