Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

I can't imagine not using class-transformer[0] or class-validator[1] in any TypeScript project that deals with external/third-party APIs, remote or not.

[0] https://www.npmjs.com/package/class-transformer [1] https://www.npmjs.com/package/class-validator



I completely agree with the more general point, that consuming external data requires a validation layer. But oh boy do I have feelings about class-validator.

Here's what it looks like to correctly annotate an array of objects with with class-validator and json-schema annotations:

  @ApiProperty({ type: Foo, isArray: true })
  @ValidateNested({ each: true })
  @Type(() => Foo)
  @IsArray()
  items: Foo[];
It's not just that you have to define everything in triplicate, it's that the failure mode for forgetting any of the above is to silently not validate your data. Unless you're very careful, you don't get the safety benefits that were the whole point of using class-validator in the first place.

If I were starting from scratch, I would instead consider either io-ts or a solution that involves a code generation step, where this entire category of risk is avoided.


I don't understand the point of transforming things to class instances, though. All of TypeScript's strengths are available without the need for things to be an actual `instanceof` something, right? Can you elaborate?

FWIW, I'm biased against `class-transformer` because we were wondering why some of our (TypeScript-driven) API endpoints were so slow, and `classToPlain` + `plainToClass` were the culprits, comprising 2/3 of the time spent. If you look at the source code for those functions, they're kind of insane.


Agreed that actually doing the transformations is a bit of a mug's game. However, TypeScript's type system treats class definitions interestingly, particularly around metadata. You can attach validation metadata to a class and pass plain objects around that structurally match that class so long as you don't define methods or a constructor.

As mentioned in my sibling comment to yours, I do this to define DTOs that are then expressed in JSON Schema and passed through ajv, and it's pretty slick. The objects being used are all just JavaScript objects, the class is just being used as a metadata holder and something you can reference/get via `design:type`/`design:paramtype`/`design:returntype`.


I can, because I use ajv and JSON Schema instead because I can trivially just take those models and use them in OAS3 documents. The web framework I've built on top of Fastify--and will be open-sourcing soonish--uses pretty simple model and property annotations to let you define your systems in those terms, and I find it to be really flexible and pleasant to work with.

EDIT: Also, as mentioned elsewhere in this thread, io-ts is a pretty good option too!


It’s the slowest validator package.

Here I have a repo benchmarking (hopefully) all of the available runtime validation packages:

https://github.com/moltar/typescript-runtime-type-benchmarks




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: