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

[BUG] TypeError in JsonDeserializer when handling Array of Maps #2761

Closed
ochrstn opened this issue Jul 23, 2024 · 9 comments
Closed

[BUG] TypeError in JsonDeserializer when handling Array of Maps #2761

ochrstn opened this issue Jul 23, 2024 · 9 comments
Assignees

Comments

@ochrstn
Copy link
Contributor

ochrstn commented Jul 23, 2024

Describe the bug

When using Ts.ED to handle an array of maps, a TypeError is thrown by the JsonDeserializer

To Reproduce

import { Controller } from "@tsed/di";
import { BodyParams } from "@tsed/platform-params";
import { CollectionOf, Get, Post, Required } from "@tsed/schema";

class Test {
  @Required()
  @CollectionOf(Map<string, string>)
  fields: Array<Map<string, string>> = [];
}

@Controller("/hello-world")
export class HelloWorldController {
  @Post("/")
  post(@BodyParams() model: Test) {

    /*
    👎🏻 Throws:
    {
      "name": "TypeError",
      "message": "this.mappers[id] is not a function",
      "status": 500,
      "errors": [],
      "stack": "TypeError: this.mappers[id] is not a function\n    at JsonDeserializer.execMapper (/private/tmp/tsed-arrayofmaps/node_modules/@tsed/json-mapper/src/domain/JsonMapperCompiler.ts:187:28)\n    at JsonDeserializer.mapItem (/private/tmp/tsed-arrayofmaps/node_modules/@tsed/json-mapper/src/domain/JsonDeserializer.ts:391:17)\n    at /private/tmp/tsed-arrayofmaps/node_modules/@tsed/json-mapper/src/domain/JsonDeserializer.ts:384:25\n    at Array.forEach (<anonymous>)\n    at JsonDeserializer.mapMap (/private/tmp/tsed-arrayofmaps/node_modules/@tsed/json-mapper/src/domain/JsonDeserializer.ts:383:23)\n    at JsonDeserializer.execMapper (/private/tmp/tsed-arrayofmaps/node_modules/@tsed/json-mapper/src/domain/JsonMapperCompiler.ts:187:28)\n    at JsonDeserializer.mapItem (/private/tmp/tsed-arrayofmaps/node_modules/@tsed/json-mapper/src/domain/JsonDeserializer.ts:391:17)\n    at /private/tmp/tsed-arrayofmaps/node_modules/@tsed/json-mapper/src/domain/JsonDeserializer.ts:372:19\n    at Array.map (<anonymous>)\n    at JsonDeserializer.mapArray (/private/tmp/tsed-arrayofmaps/node_modules/@tsed/json-mapper/src/domain/JsonDeserializer.ts:371:29)"
    }
    */

    return model;
  }

  @Get("/")
  get() {
    const result = new Test();
    result.fields = [
      new Map(Object.entries({ de: "Deutsch", en: "English", fr: "Français" })),
      new Map(Object.entries({ es: "Español", it: "Italiano" })),
    ];
    return result;

    /*
    👍🏻  Returns:
    {
      "fields": [
          {
              "de": "Deutsch",
              "en": "English",
              "fr": "Français"
          },
          {
              "es": "Español",
              "it": "Italiano"
          }
      ]
    }
    */
  }
}

Expected behavior

Should deserialize correctly

Code snippets

No response

Repository URL example

No response

OS

macOS

Node version

v18.18.2

Library version

7.77.0

Additional context

No response

@Romakita
Copy link
Collaborator

Romakita commented Jul 23, 2024

Hello @ochrstn

I think your example isn't valid. Try that:

class Test {
  @Required()
  @CollectionOf(Map)
  fields: Array<Map<string, string>> = [];
}

See you

@ochrstn
Copy link
Contributor Author

ochrstn commented Jul 24, 2024

Hello @ochrstn

I think your example isn't valid. Try that:

class Test {
  @Required()
  @CollectionOf(Map)
  fields: Array<Map<string, string>> = [];
}

See you

same problem

@Romakita
Copy link
Collaborator

So @ochrstn these usage isn't officially supported by tsed in fact, because describing an array of map of string (something else isn't possible with decorators).

I'll take a time to give you a workaround.
See you

@ochrstn
Copy link
Contributor Author

ochrstn commented Jul 24, 2024

So @ochrstn these usage isn't officially supported by tsed in fact, because describing an array of map of string (something else isn't possible with decorators).

I'll take a time to give you a workaround. See you

Thanks for clarifying.

Thats my workaround so far:

@AdditionalProperties(true)
class Field {
  [key: string]: string;
}

class Test {
  @Required()
  @CollectionOf(Field)
  fields: Array<Field> = [];
}

This works for my usecase so far. Any additional ideas?

@Romakita
Copy link
Collaborator

Maybe this workaround should works:

    const schema = array().items(map().additionalProperties(String))

    class Test {
      @Schema(schema.toJSON())
      @CollectionOf(Map)
      @OnDeserialize(o => o.map((i) => new Map(Object.entries(i))))
      @OnSerialize(o => o.map(i => Object.fromEntries(i.entries())))
      fields: Map<string, string>[] = [];
    }

@Romakita
Copy link
Collaborator

Romakita commented Jul 24, 2024

But if you don't care about having an array of map:

const schema = array().items(object().additionalProperties(string()))

    class Test {
      @Schema(schema.toJSON())
      @CollectionOf(Object)
      fields: Record<string, string>[] = [];
    }

Romakita added a commit that referenced this issue Jul 24, 2024
@Romakita
Copy link
Collaborator

@ochrstn This PR should improve the DX when you declare a Collection of Map:

#2762

Copy link

🎉 Are you happy?

If you appreciated the support, know that it is free and is carried out on personal time ;)

A support, even a little bit makes a difference for me and continues to bring you answers!

github opencollective

@Romakita
Copy link
Collaborator

🎉 This issue has been resolved in version 7.77.1 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants