{"id":120,"date":"2020-11-16T12:47:33","date_gmt":"2020-11-16T11:47:33","guid":{"rendered":"https:\/\/info.edython.eu\/?p=120"},"modified":"2020-11-16T13:49:04","modified_gmt":"2020-11-16T12:49:04","slug":"class-decorators-vs-mixins","status":"publish","type":"post","link":"https:\/\/info.edython.eu\/index.php\/2020\/11\/16\/class-decorators-vs-mixins\/","title":{"rendered":"Class decorators vs mixins"},"content":{"rendered":"\n<p>Class decorators are an experimental feature of typescript 4.0 and mixins were supported since typescript 2.2 at least. Unfortunately class decorators do have drawbacks with respect to the type recognition because added attributes are not recognized as is. Here is a comparison of class decorators and mixins after an excellent <a href=\"https:\/\/mariusschulz.com\/blog\/mixin-classes-in-typescript\">article<\/a> from Marius Shulz.<\/p>\n\n\n\n<p>We see on two examples how using decorators is more verbose than using mixins.<\/p>\n\n\n\n<h2>Timestamps<\/h2>\n\n\n\n<p>Timestamping instances at creation time (<a href=\"https:\/\/www.typescriptlang.org\/play?jsx=0&amp;module=0&amp;ts=4.0.5#code\/GYVwdgxgLglg9mABAFRgWwKYGcoEM0AOGAJgDwBQiKAQrlhohgB5QZjFaIDeiYGA7gAoAdKNwAnAOZYAXIlxgAngG0AugEo5XAL6Jt5AHyDa9OchMZ13SonEYoIcUggAbOp2at2nC9apVYTBx8AkQAXkQAEVxWYTA4IXUbfX0AelTEAGE7GIZcXgFEV3dEACNFRDQYJhgwSUQAA1QgvEISBsRaqDh5JAUERTQ4EE5irCxyCAQcFHRsVqJiAFV6cXDZlpCSQTHOLhspsBxxEGg4cUECEFKXGAhefAw5Y9rJKx1ybST0xABJI7wYFguUQUAAFgw+PxGs15ltlqsOrtJtMoIgRhg1hEoRs4W0EZjBAAiABScDBSEicAwRKShywcBcGGELjgkkEGPEcUedOmjOZrPZnOEgTxBCSQA\">TS playground<\/a>).<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"typescript\" class=\"language-typescript\">function Timestamped&lt;\n  TBase extends { new(...args: any[]): {} }\n>(Base: TBase) {\n  return class extends Base {\n    timestamp = Date.now()\n  }\n}\n\/\/ Create a new class by mixing `Timestamped` into an anonymous class\nconst TimestampedUser = Timestamped(class {\n  constructor(public name: string) {}\n})\n\/\/ Instantiate the new `TimestampedUser` class\nconst user = new TimestampedUser(\"John Doe\")\nconsole.log(user.name)\nconsole.log(user.timestamp)\n<\/code><\/pre>\n\n\n\n<p>Here is the same functionality with  a decorator (<a href=\"https:\/\/www.typescriptlang.org\/play?jsx=0&amp;module=0&amp;ts=4.0.5#code\/JYOwLgpgTgZghgYwgAgJIBVgFsIGcxxYAOEAJsgN4BQyyY2eBxAXMgCJyRUC+VMAriAT0A9iGSYc+QiVIAeGhIBCcXCggAPSCFK5KyEBADuACgB0FuFADmuVnBABPANoBdAJSsK3ZLwB8JipqrOhBEO6UilAQYPxQ4ggANqp6mtq6yGHI2ESJEDjgehgM0sRkkbS09FJMRMgAvOycEGYgIqbuiry8APQ9yADC0c3IcAbGyEkpyABGjshYwBqg1sgABpKMMmRr2eAio+IOYo5YIvx6U7i4VAACm6WyVFd6D7VkAKpqUNS0CGL4KD8YQiKAmIj8GaJYAIAyECCsQErCLeHhUPpoEDScDAEZgAAWKEMRnWb22pC+0F2L2eALAyAu0Aa4xJZLKFO+JgARAApET48RsEQQLkRVQSErvDlMgBkaDZT3+WJEeTMiRE1hMjKgrXhnSVuBVLXVmu1ZmqW2InSAA\" data-type=\"URL\" data-id=\"https:\/\/www.typescriptlang.org\/play?jsx=0&amp;module=0&amp;ts=4.0.5#code\/JYOwLgpgTgZghgYwgAgJIBVgFsIGcxxYAOEAJsgN4BQyyY2eBxAXMgCJyRUC+VMAriAT0A9iGSYc+QiVIAeGhIBCcXCggAPSCFK5KyEBADuACgB0FuFADmuVnBABPANoBdAJSsK3ZLwB8JipqrOhBEO6UilAQYPxQ4ggANqp6mtq6yGHI2ESJEDjgehgM0sRkkbS09FJMRMgAvOycEGYgIqbuiry8APQ9yADC0c3IcAbGyEkpyABGjshYwBqg1sgABpKMMmRr2eAio+IOYo5YIvx6U7i4VAACm6WyVFd6D7VkAKpqUNS0CGL4KD8YQiKAmIj8GaJYAIAyECCsQErCLeHhUPpoEDScDAEZgAAWKEMRnWb22pC+0F2L2eALAyAu0Aa4xJZLKFO+JgARAApET48RsEQQLkRVQSErvDlMgBkaDZT3+WJEeTMiRE1hMjKgrXhnSVuBVLXVmu1ZmqW2InSAA\">TS playground<\/a>)<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"typescript\" class=\"language-typescript\">interface ITimestamped {\n  timestamp: Date\n}\nfunction Timestamped&lt;\n  TBase extends { new(...args: any[]): {} }\n>(Base: TBase) {\n  return class extends Base implements ITimestamped {\n    timestamp = Date.now()\n  }\n}\n\/\/ Create a new class by decorating class `TimestampedUser`\n@Timestamped\nclass TimestampedUser{\n  constructor(public name: string) {}\n}\n\/\/ Instantiate the new `TimestampedUser` class\nconst user = new TimestampedUser(\"John Doe\") as TimestampedUser &amp; ITimestamped\nconsole.log(user.name)\nconsole.log(user.timestamp)<\/code><\/pre>\n\n\n\n<h2>With a Constructor<\/h2>\n\n\n\n<h3>Mixins version<\/h3>\n\n\n\n<p> (<a href=\"https:\/\/www.typescriptlang.org\/play?jsx=0&amp;module=0&amp;ts=4.0.5#code\/GYVwdgxgLglg9mABAFQIYHN0FMAmAeAKERQCFUBnLRLADyizB3MQG9EwsB3ACgDp-UAJ3TkAXIlRgAngG0AugEpxLAL6IVBAHzcylccl1YFrIokFYoIQUggAbCs1r1GzQyeLEoGAPzjyUQRgwdFNiCAR-QRBoOEE+AWExCWl5YxZQj3IQAAcsOP5eIREFDM9BKVYoAAsYcl4vdEQAXglEmQBGOQ0PD2Ag1FtbCtUM7vUCDQB6ScQAYXNUegl2LkQ7B0QAIwqAWxgaIMaAAzRMXCPEIKg4ZOSEKR24EGZ18nICcLB-FAxsHABVSiCZo-M44bivZjpYhgVA7LB+AKHUyfSLRa75BIicSSWSKdweALDaq1Xiw+EgorkGQABi6GT6sMGwzGGhUJVRUEQzzyII4nFBf0BeW4ACIAFKSKgAETgWFFABpEKKAFZSnBy0UciJwWxYXi2ODobg8wRkuFGD46vUGo0moH1DAlIA\">TS playground<\/a>)<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"typescript\" class=\"language-typescript\">function Tagged&lt;\n  TBase extends { new(...args: any[]): {} }\n>(Base: TBase) {\n  return class extends Base {\n    tag?: string\n    constructor(...args: any[]) {\n      super(...args)\n      try {this.tag = args[1]}\n      finally {}\n    }\n  }\n}\n\/\/ Create a new class by mixing `Tagged` into an anonymous class\nconst TaggedUser = Tagged(class {\n  name: string\n  constructor(...args: any[]) {\n    try {this.name = args[0]}\n    finally {}\n  }\n})\nconst user = new TaggedUser(\"Jane Doe\", \"janedoe\")\nconsole.log(user.name)\nconsole.log(user.tag)\n<\/code><\/pre>\n\n\n\n<h3>Nota bene<\/h3>\n\n\n\n<p>In the previous code, we have two constructors. TypeScript implicitly forces them to have somehow the same signature. In that example, we also added a new argument to the constructor of the class obtained by mixins.<\/p>\n\n\n\n<h3>Class decorator version<\/h3>\n\n\n\n<p><a href=\"https:\/\/www.typescriptlang.org\/play?declaration=false&amp;jsx=0&amp;module=0&amp;ts=4.0.5#code\/JYOwLgpgTgZghgYwgAgJIBU4HMsQCbIDeAUMsmNgPwBcyAzmFKFsQL7EwCuICYwA9iGSYc+ADylhAITh0UEAB6QQeOkWQgIAdwAUAOgNwoWOrTggAngG0AugEpahVsnYA+HTLm10niHaKSUBBgnFBCCAA2smqKyqrIvgFkZBRYNPSMzJJkCIIMUJy8-FD6hsamyObW9knJZHScAA7QpXpGJnbZyYwWRGAAFsB0eqnIALyV5VYAjDbsdWQwoHAREb1OXfMubMQA9LvIAMJBcJCVGtrIkdHIAEa9eBC5UKdZAAIiuHjE13Rqn-gAKpyKC1EBwAC2EFo+SyOTyjEKYGKrXaFSqtn8JDqPT6g2G4Kh40mJisAAY5l0luDVustux2LkQAxkJwQcTNFphNgvsCWgAiABS5hQABF+BB+QAaZD8gBWIrwEv5-lk3NEeD5oIAZGgAd8mXR+BEIHoIvwsDo2dA9IS-D88sbTebLdaoCNsJ0gA\">TS playground<\/a><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"typescript\" class=\"language-typescript\">interface ITagged {\n  tag?: string\n}\nfunction Tagged&lt;\n  TBase extends { new(...args: any[]): {} }\n>(Base: TBase) {\n  return class extends Base {\n    tag?: string\n    constructor(...args: any[]) {\n      super(...args)\n      try {this.tag = args[1]}\n      finally {}\n    }\n  }\n}\n\/\/ Create a new class by mixing `Tagged` into an anonymous class\n@Tagged\nclass TaggedUser {\n  name: string\n  constructor(...args: any[]) {\n    try {this.name = args[0]}\n    finally {}\n  }\n}\nconst user = new TaggedUser(\"Jane Doe\", \"janedoe\") as TaggedUser &amp; ITagged\nconsole.log(user.name)\nconsole.log(user.tag)\n<\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Class decorators are an experimental feature of typescript 4.0 and mixins were supported since typescript 2.2 at least. Unfortunately class decorators do have drawbacks with respect to the type recognition because added attributes are not recognized as is. Here is a comparison of class decorators and mixins after an excellent article from Marius Shulz. We &hellip; <a href=\"https:\/\/info.edython.eu\/index.php\/2020\/11\/16\/class-decorators-vs-mixins\/\" class=\"more-link\">Continuer la lecture<span class=\"screen-reader-text\"> de &laquo;&nbsp;Class decorators vs mixins&nbsp;&raquo;<\/span><\/a><\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[5],"tags":[],"_links":{"self":[{"href":"https:\/\/info.edython.eu\/index.php\/wp-json\/wp\/v2\/posts\/120"}],"collection":[{"href":"https:\/\/info.edython.eu\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/info.edython.eu\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/info.edython.eu\/index.php\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/info.edython.eu\/index.php\/wp-json\/wp\/v2\/comments?post=120"}],"version-history":[{"count":8,"href":"https:\/\/info.edython.eu\/index.php\/wp-json\/wp\/v2\/posts\/120\/revisions"}],"predecessor-version":[{"id":136,"href":"https:\/\/info.edython.eu\/index.php\/wp-json\/wp\/v2\/posts\/120\/revisions\/136"}],"wp:attachment":[{"href":"https:\/\/info.edython.eu\/index.php\/wp-json\/wp\/v2\/media?parent=120"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/info.edython.eu\/index.php\/wp-json\/wp\/v2\/categories?post=120"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/info.edython.eu\/index.php\/wp-json\/wp\/v2\/tags?post=120"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}