<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Ilias Gazdaliev</title>
    <description>The latest articles on DEV Community by Ilias Gazdaliev (@eljoy).</description>
    <link>https://dev.to/eljoy</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F268316%2F30421df2-9232-4d22-bfe1-c5905222fe81.jpeg</url>
      <title>DEV Community: Ilias Gazdaliev</title>
      <link>https://dev.to/eljoy</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/eljoy"/>
    <language>en</language>
    <item>
      <title>Your decorator library silently breaks on Vite. Here's why (and a fix) — ts-jackson 2.0</title>
      <dc:creator>Ilias Gazdaliev</dc:creator>
      <pubDate>Tue, 28 Jul 2026 10:12:46 +0000</pubDate>
      <link>https://dev.to/eljoy/your-decorator-library-silently-breaks-on-vite-heres-why-and-a-fix-ts-jackson-20-fdg</link>
      <guid>https://dev.to/eljoy/your-decorator-library-silently-breaks-on-vite-heres-why-and-a-fix-ts-jackson-20-fdg</guid>
      <description>&lt;p&gt;You have a class that maps an API response. It works perfectly in your old webpack + ts-loader project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Serializable&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Event&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;JsonProperty&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="nx"&gt;startsAt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;

  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;JsonProperty&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="nx"&gt;attendees&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You move to Vite. It compiles. It runs. No warnings. And then, somewhere far from this file, production throws &lt;code&gt;event.startsAt.getTime is not a function&lt;/code&gt; — because &lt;code&gt;startsAt&lt;/code&gt; is quietly a plain string now, and &lt;code&gt;attendees&lt;/code&gt; might be one too.&lt;/p&gt;

&lt;p&gt;Nothing crashed at the mapping site. That's what makes this failure mode nasty. Here's what's actually going on.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why: the two-flag magic trick
&lt;/h2&gt;

&lt;p&gt;Every classic decorator-metadata library — class-transformer, TypeORM, typescript-json-serializer, ts-jackson 1.x — relies on &lt;strong&gt;two&lt;/strong&gt; tsconfig flags:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"experimentalDecorators"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"emitDecoratorMetadata"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first enables the legacy decorator syntax. The second is the magic one: it makes the TypeScript compiler look at your type annotation (&lt;code&gt;startsAt: Date&lt;/code&gt;) and secretly emit a runtime value next to the decorator:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// what tsc actually generates (simplified)&lt;/span&gt;
&lt;span class="nb"&gt;Reflect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;design:type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's how &lt;code&gt;@JsonProperty()&lt;/code&gt; with zero configuration knows it should build a &lt;code&gt;Date&lt;/code&gt;. The type annotation — normally erased at compile time — gets smuggled into the runtime.&lt;/p&gt;

&lt;p&gt;Here's the catch: &lt;strong&gt;emitting &lt;code&gt;design:type&lt;/code&gt; requires actually resolving types.&lt;/strong&gt; Is &lt;code&gt;startsAt&lt;/code&gt;'s annotation a class? An interface? An import alias? Answering that means type-checking the program.&lt;/p&gt;

&lt;p&gt;Now recall why esbuild is fast: it transpiles file-by-file and &lt;em&gt;never type-checks&lt;/em&gt;. It just strips annotations. So esbuild doesn't implement &lt;code&gt;emitDecoratorMetadata&lt;/code&gt; — not as an oversight, but because implementing it would require becoming the thing it was built to replace. And Vite transforms your TypeScript with esbuild.&lt;/p&gt;

&lt;p&gt;The result on a stock Vite project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nb"&gt;Reflect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getMetadata&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;design:type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;startsAt&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// undefined&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The decorator still runs. Metadata is just… missing. Your mapping library falls back to "no type known", passes the raw JSON value through, and you get a string where a &lt;code&gt;Date&lt;/code&gt; should be. No error at the site of the lie — only downstream, at runtime, in whatever code first trusts the type.&lt;/p&gt;

&lt;p&gt;(SWC, for the record, &lt;em&gt;can&lt;/em&gt; emit decorator metadata, but it's opt-in config — stock setups frequently miss it too.)&lt;/p&gt;

&lt;h2&gt;
  
  
  The fix: decorators that don't need a compiler accomplice
&lt;/h2&gt;

&lt;p&gt;Since 5.0 — with decorator metadata following in 5.2, TypeScript's &lt;em&gt;default&lt;/em&gt; decorator mode — no flags at all — implements the &lt;strong&gt;TC39 standard decorators proposal&lt;/strong&gt;, together with the decorator-metadata proposal (&lt;code&gt;Symbol.metadata&lt;/code&gt;). Standard decorators are pure runtime semantics: the decorator receives a context object, stores whatever metadata it wants, and no compiler magic is involved anywhere.&lt;/p&gt;

&lt;p&gt;Which means they work under esbuild. And Vite. And every bundler that can handle modern JavaScript — because there's nothing to implement beyond the syntax itself.&lt;/p&gt;

&lt;p&gt;There's one honest trade-off: the standard has &lt;strong&gt;no equivalent of &lt;code&gt;design:type&lt;/code&gt;&lt;/strong&gt;, by design — JavaScript has no types at runtime, and TC39 doesn't standardize compiler tricks. So type inference from annotations is gone; where conversion matters, you declare the type explicitly.&lt;/p&gt;

&lt;h2&gt;
  
  
  ts-jackson 2.0: both worlds, auto-detected
&lt;/h2&gt;

&lt;p&gt;I just shipped &lt;a href="https://github.com/Eljoy/ts-jackson" rel="noopener noreferrer"&gt;ts-jackson 2.0&lt;/a&gt;, and the headline feature is exactly this: it supports &lt;strong&gt;both decorator modes&lt;/strong&gt;, and detects at runtime which one invoked it. Same imports, same API.&lt;/p&gt;

&lt;p&gt;Legacy mode (tsc, flags on) — full type inference, exactly like v1:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Serializable&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Event&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;JsonProperty&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="nx"&gt;startsAt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;            &lt;span class="c1"&gt;// inferred from the annotation&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Standard mode (Vite, esbuild, no flags) — explicit types:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Serializable&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Event&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;JsonProperty&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="nx"&gt;startsAt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;

  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;JsonProperty&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;elementType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Image&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;  &lt;span class="c1"&gt;// elementType implies an array&lt;/span&gt;
  &lt;span class="nx"&gt;images&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Image&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you're not familiar with ts-jackson from the &lt;a href="https://dev.to/eljoy/introducing-ts-jackson-a-typescript-library-to-deserializeserialize-deeply-nested-json-structures-1o1"&gt;original post&lt;/a&gt; &lt;/p&gt;

</description>
      <category>javascript</category>
      <category>programming</category>
      <category>typescript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Introducing ts-jackson, a typescript library to deserialize/serialize deeply nested json structures.</title>
      <dc:creator>Ilias Gazdaliev</dc:creator>
      <pubDate>Tue, 10 May 2022 18:40:10 +0000</pubDate>
      <link>https://dev.to/eljoy/introducing-ts-jackson-a-typescript-library-to-deserializeserialize-deeply-nested-json-structures-1o1</link>
      <guid>https://dev.to/eljoy/introducing-ts-jackson-a-typescript-library-to-deserializeserialize-deeply-nested-json-structures-1o1</guid>
      <description>&lt;p&gt;&lt;a href="https://www.npmjs.com/package/ts-jackson"&gt;ts-jackson&lt;/a&gt; is a json seralization library aimed to effortlessly handle serialization/deserialization of deeply nested json structures.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const jsonData = {
  images: {
    items: [
      {
        height: 300,
        url:
          'https://i.scdn.co/image/ab67616d0000b27380368f0aa8f90c51674f9dd2',
        width: 300,
      },
      {
        height: 640,
        url:
          'https://i.scdn.co/image/ab67616d00001e0280368f0aa8f90c51674f9dd2',
        width: 640,
      },
    ],
  },
}

@Serializable()
class Playlist {
  @JsonProperty('images.items[1]')
  readonly backgroundImage: Image
}

const deserialized = deserialize(jsonData, Playlist)
// Playlist {
//   backgroundImage: Image {
//     height: 640,
//     width: 640,
//     url: 'https://i.scdn.co/image/ab67616d00001e0280368f0aa8f90c51674f9dd2'
//   }
// }
const serialized = serialize(deserialized)
// {
//   images: {
//     items: [undefined, {
//       height: 640,
//       width: 640,
//       url: 'https://i.scdn.co/image/ab67616d00001e0280368f0aa8f90c51674f9dd2',
//     }],
//   },
// }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It uses &lt;a href="https://lodash.com/"&gt;Lodash&lt;/a&gt; &lt;code&gt;_.get/_.set&lt;/code&gt; to resolve property paths and supports every pattern provided by Lodash.&lt;/p&gt;

&lt;p&gt;You can check out the full api here:&lt;br&gt;
&lt;a href="https://github.com/Eljoy/ts-jackson"&gt;https://github.com/Eljoy/ts-jackson&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Every feedback is truly welcomed. :)&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>javascript</category>
      <category>json</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
