{"id":134,"date":"2020-11-16T17:40:56","date_gmt":"2020-11-16T16:40:56","guid":{"rendered":"https:\/\/info.edython.eu\/?p=134"},"modified":"2020-11-16T17:40:56","modified_gmt":"2020-11-16T16:40:56","slug":"overriding-a-method-signature-with-optional-arguments","status":"publish","type":"post","link":"https:\/\/info.edython.eu\/index.php\/2020\/11\/16\/overriding-a-method-signature-with-optional-arguments\/","title":{"rendered":"Overriding a method signature with optional arguments"},"content":{"rendered":"\n<p>When overriding a method, we may want to add a new formal argument. This may be the case for constructors. If the signature is mixing required and optional arguments, things may become difficult, without mentioning class mixins and decorators.<\/p>\n\n\n\n<p>When you have a strongly designed base class, you can safely override a method in the subclass and choose there whatever signature you want. But if you happen to change the signature in the base class, you must propagate the changes down the hierarchy to update accordingly all the overridden methods&rsquo; signatures. This is a change in design that may have big consequences, and as such is prone to bugs.<\/p>\n\n\n\n<h2>Required and optional arguments<\/h2>\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\/MYGwhgzhAEAKYCcCmA7ALtA3gKGtNSEaAFAGYD25AjAFzREICWKA5gDTQBGit9aTraAF5oAcm4IqogJRZceaMHIoI5EEgB0IcizKUqHCVWnyAvtnMokAdziJUJaRoJFioitRnZQkGAGEAC0YQABNoJAAPAhQQmHhkdDk8FxIPXgZmdmgPACY6DNZDHnz+TOExI1EihDy+ARZy8UQcmSSFCABXAAckBGdCVP1q43k8JRU1TW1dXOqckzxzc3GiRSDQ8qtbQOCQ4hNgdZD+13d9KrFcr0Pdk5Izzw4HlqfuAC8pA6O7tzSL54uHRiSFIzCQIVeYDeLRMQA\">TS playground<\/a><\/p>\n\n\n\n<p>Here is a base class<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"typescript\" class=\"language-typescript\">class Parent {\n  test(foo1: string, bar1: string = 'bar1') {\n    console.log(foo1, bar1)\n  }\n}\nnew Parent().test('foo1')\n<\/code><\/pre>\n\n\n\n<p>we override <code>test<\/code> adding both a required and an optional parameter<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"typescript\" class=\"language-typescript\">class Child extends Parent {\n  test(foo1: string, foo2: string, bar1: string = 'bar1', bar2: string = 'bar2') {\n    super.test(foo1, bar1)\n    console.log(foo2, bar2)\n  }\n}\nconst child = new Child()\nchild.test('foo1', 'foo2')\nchild.test('foo1', 'foo2', 'baz1')\nchild.test('foo1', 'foo2', undefined, 'baz2')\n<\/code><\/pre>\n\n\n\n<ul><li>The default value of the <code>bar1<\/code> is defined twice<\/li><li>We must explicitly use <code>undefined<\/code> in order to specify only the second optional argument.<\/li><li>No more than 3 or 4 arguments stay legible.<\/li><\/ul>\n\n\n\n<h2>Key Valued arguments<\/h2>\n\n\n\n<p>When positional arguments are not practical nor efficient, we can make use of key valued arguments. Each method has a unique argument with a well defined type. Here is the previous example revisited.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"typescript\" class=\"language-typescript\">type test_r = {\n  foo1: string\n  bar1?: string\n}\nclass Parent {\n  test($: test_r) {\n    console.log($.foo1, $.bar1 || 'bar1')\n  }\n}\nnew Parent().test({\n  foo1: 'foo1'\n})\n<\/code><\/pre>\n\n\n\n<p>In order to override the <code>test<\/code> method, we start by extending <code>test_r<\/code>.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"\">type test_r_r = test_r &amp; {\n  foo2: string\n  bar2?: string\n}\nclass Child extends Parent {\n  test($: test_r_r) {\n    super.test($)\n    console.log($.foo2, $.bar2 || 'bar2')\n  }\n}\nconst child = new Child()\nconst foo1 = 'foo1'\nconst foo2 = 'foo2'\nconst bar1 = 'baz1'\nconst bar2 = 'baz2'\nchild.test({foo1, foo2})\nchild.test({foo1, foo2, bar1})\nchild.test({foo1, foo2, bar2})\n<\/code><\/pre>\n\n\n\n<ul><li>This is more verbose<\/li><li>this is more legible<\/li><li>The default values are managed in the code, not in the arguments (in general, composed default values must be managed in the code).<\/li><\/ul>\n\n\n\n<h2>Class Mixins<\/h2>\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\/C4TwDgpgBAdhDuB9ATlAvFA3gKClA2gCQBcUAzsMgJYwDmAuqQIYwi6xMC2EpF1d2AL7YAxgBsmZMlACqZCKhx4YXHuUo1a7EQHsYfAK4jgO5AAoSsBCgCUWdnmAALKmQB0K7uiiEPq9sLCuvrAUAbyqBhw8LIRZkoc3KQARABSOk4wUAAiOhDJQjaiemQ6YhBuYjq0ZuEKftxF2KCQUAAqTLS0EAAmKAA8AEoAfN6DUABk9o6dvBoCwgBmBjDGVHrtnd09-extAEKS0BAAHsAQMD3SmFbwZm4PTMi0ZMys+PQ2pJiCUIIANOxoohBthhmZDvJSAcjnYEsgIMADMgsuJJNJTudLtJIdAEjNaAB+Ob8LR4PDBQzGUz3R7PV5QFggD5whzkymhQjeJ4vfAABnojOkHS6vQGwJGbLwZAMkHMhCK5PJzlcbmAnW8vnVZPJwjwgWw2AA9EaoABhBFMc6M25QNFSKAAIxAUE4VBOmigAAMRdsvVAaCZGVkWHoQJwdOE7RIpKIY8Ktr05AooJiLldNqKemZk8hWRSSpQjCZ5dDE31kP1gchhvnyTK5RZFX8hIaOVBtdtEHVIrbfUm4glPGo0ixoLl8oCCaQAOQAKzHPTyM8KbZKZQqVRqnbFPYaECKlI3lWqZh3fT32qKQA\">TS playground<\/a><\/p>\n\n\n\n<p>We first define a <code>User<\/code> class with a key valued unique constructor argument<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"typescript\" class=\"language-typescript\">type new_r = {\n  [$: string]: any\n  name: string\n}\nclass User {\n  name: string\n  constructor($: new_r) {\n    this.name = $.name\n  }\n}\nconst user = new User({\n  name: \"John Doe\"\n})\nconsole.log(user.name)<\/code><\/pre>\n\n\n\n<p>Then we define a <code>Tagged<\/code> mixins function<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"typescript\" class=\"language-typescript\">type Tagged_r&lt;R> = R &amp; {\n  tag: string\n}\nfunction Tagged&lt;\n  TBase extends { new(...args: any[]): {} },\n  new_R\n>(Base: TBase) {\n  return class extends Base {\n    tag?: string\n    constructor(...args: any[]) {\n      const $ = args[0] as Tagged_r&lt;new_R>\n      super($)\n      this.tag = $.tag\n    }\n  }\n}\n\/\/ Create a new class by mixing `Tagged` into an anonymous class that we extend\n\/\/ to restrict the constructor signature.\nclass TaggedUser extends Tagged(User) {\n  constructor($: Tagged_r&lt;new_r>) {\n    super($)\n  }\n}\nconst tagged_user = new TaggedUser({\n  name: \"Jane Doe\",\n  tag: 'janedoe'\n})\nconsole.log(tagged_user.name)\nconsole.log(tagged_user.tag)<\/code><\/pre>\n\n\n\n<p>We have more possibilities<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"typescript\" class=\"language-typescript\">new User({\n  name: \"Jane Doe\",\n  tag: 'janedoe'\n})\nnew User(user)\nnew User(tagged_user)\nnew TaggedUser(tagged_user)<\/code><\/pre>\n\n\n\n<ul><li><code>new_r<\/code> accepts any string key to allow more possibilities<\/li><li>there is one &lsquo;do nothing&rsquo; class layer: not a very clean design<\/li><\/ul>\n","protected":false},"excerpt":{"rendered":"<p>When overriding a method, we may want to add a new formal argument. This may be the case for constructors. If the signature is mixing required and optional arguments, things may become difficult, without mentioning class mixins and decorators. When you have a strongly designed base class, you can safely override a method in the &hellip; <a href=\"https:\/\/info.edython.eu\/index.php\/2020\/11\/16\/overriding-a-method-signature-with-optional-arguments\/\" class=\"more-link\">Continuer la lecture<span class=\"screen-reader-text\"> de &laquo;&nbsp;Overriding a method signature with optional arguments&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":[1],"tags":[],"_links":{"self":[{"href":"https:\/\/info.edython.eu\/index.php\/wp-json\/wp\/v2\/posts\/134"}],"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=134"}],"version-history":[{"count":2,"href":"https:\/\/info.edython.eu\/index.php\/wp-json\/wp\/v2\/posts\/134\/revisions"}],"predecessor-version":[{"id":137,"href":"https:\/\/info.edython.eu\/index.php\/wp-json\/wp\/v2\/posts\/134\/revisions\/137"}],"wp:attachment":[{"href":"https:\/\/info.edython.eu\/index.php\/wp-json\/wp\/v2\/media?parent=134"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/info.edython.eu\/index.php\/wp-json\/wp\/v2\/categories?post=134"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/info.edython.eu\/index.php\/wp-json\/wp\/v2\/tags?post=134"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}