<p dir="auto">It would be useful to be able to declare optional properties on a class, similar to how it works for interfaces.  This would allow more expressive structural subtyping with plain classes:</p>
<div class="highlight highlight-source-ts notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="class Name {
  first: string;
  middle?: string;
  last: string;
}

function printName(name: Name) {
  //...
}

printName({first: &quot;First&quot;, last: &quot;Last&quot; });
"><pre class="notranslate"><span class="pl-k">class</span> <span class="pl-smi">Name</span> <span class="pl-kos">{</span>
  <span class="pl-c1">first</span>: <span class="pl-smi">string</span><span class="pl-kos">;</span>
  <span class="pl-c1">middle</span>?: <span class="pl-smi">string</span><span class="pl-kos">;</span>
  <span class="pl-c1">last</span>: <span class="pl-smi">string</span><span class="pl-kos">;</span>
<span class="pl-kos">}</span>

<span class="pl-k">function</span> <span class="pl-en">printName</span><span class="pl-kos">(</span><span class="pl-s1">name</span>: <span class="pl-smi">Name</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
  <span class="pl-c">//...</span>
<span class="pl-kos">}</span>

<span class="pl-en">printName</span><span class="pl-kos">(</span><span class="pl-kos">{</span><span class="pl-c1">first</span>: <span class="pl-s">"First"</span><span class="pl-kos">,</span> <span class="pl-c1">last</span>: <span class="pl-s">"Last"</span> <span class="pl-kos">}</span><span class="pl-kos">)</span><span class="pl-kos">;</span></pre></div>
<p dir="auto">Technically, this is already possible with the recent change to allow merging interfaces and non-ambient classes:</p>
<div class="highlight highlight-source-ts notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="interface Name {
  middle?: string;
}

class Name { 
  first: string;
  last: string
}"><pre class="notranslate"><span class="pl-k">interface</span> <span class="pl-smi">Name</span> <span class="pl-kos">{</span>
  <span class="pl-c1">middle</span>?: <span class="pl-smi">string</span><span class="pl-kos">;</span>
<span class="pl-kos">}</span>

<span class="pl-k">class</span> <span class="pl-smi">Name</span> <span class="pl-kos">{</span> 
  <span class="pl-c1">first</span>: <span class="pl-smi">string</span><span class="pl-kos">;</span>
  <span class="pl-c1">last</span>: <span class="pl-smi">string</span>
<span class="pl-kos">}</span></pre></div>
<p dir="auto">However, it's not very DRY for this use case.  Now, you might ask, why not just use an interface and not a class when dealing with plain objects with optional properties?  Because interfaces are not real values, which means that they cannot be passed around or be decorated, both of which are often useful.</p>
<p dir="auto">My motivation for requesting this comes from writing a wrapper library for Immutable.js.  I'm trying to create a nice way for library users to declare data items and update them.  Here's an abbreviated example of how I would like it to look:</p>
<div class="highlight highlight-source-ts notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="class TodoData {
  @prop text?: string;
  @prop completed?: boolean;
}

class Todo extends TypedMap(TodoData) { }

// todoMap is a typed map representing a Todo
var todo = Todo.create();

// The optional properties allow a nice typed syntax for updating the map
todoMap = todoMap.set({text: &quot;Hello&quot;});

// The @prop decorator was used to run Object.defineProperty on each declared property
console.log(todoMap.text);"><pre class="notranslate"><span class="pl-k">class</span> <span class="pl-smi">TodoData</span> <span class="pl-kos">{</span>
  @<span class="pl-s1">prop</span> <span class="pl-c1">text</span>?: <span class="pl-smi">string</span><span class="pl-kos">;</span>
  @<span class="pl-s1">prop</span> <span class="pl-c1">completed</span>?: <span class="pl-smi">boolean</span><span class="pl-kos">;</span>
<span class="pl-kos">}</span>

<span class="pl-k">class</span> <span class="pl-smi">Todo</span> <span class="pl-k">extends</span> <span class="pl-smi">TypedMap</span><span class="pl-kos">(</span><span class="pl-smi">TodoData</span><span class="pl-kos">)</span> <span class="pl-kos">{</span> <span class="pl-kos">}</span>

<span class="pl-c">// todoMap is a typed map representing a Todo</span>
<span class="pl-k">var</span> <span class="pl-s1">todo</span> <span class="pl-c1">=</span> <span class="pl-smi">Todo</span><span class="pl-kos">.</span><span class="pl-en">create</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">;</span>

<span class="pl-c">// The optional properties allow a nice typed syntax for updating the map</span>
<span class="pl-s1">todoMap</span> <span class="pl-c1">=</span> <span class="pl-s1">todoMap</span><span class="pl-kos">.</span><span class="pl-en">set</span><span class="pl-kos">(</span><span class="pl-kos">{</span><span class="pl-c1">text</span>: <span class="pl-s">"Hello"</span><span class="pl-kos">}</span><span class="pl-kos">)</span><span class="pl-kos">;</span>

<span class="pl-c">// The <span class="pl-k">@prop</span> decorator was used to run Object.defineProperty on each declared property</span>
<span class="pl-smi">console</span><span class="pl-kos">.</span><span class="pl-en">log</span><span class="pl-kos">(</span><span class="pl-s1">todoMap</span><span class="pl-kos">.</span><span class="pl-c1">text</span><span class="pl-kos">)</span><span class="pl-kos">;</span></pre></div>
<p dir="auto">I have problem of a non-DRY situation. I have <code class="notranslate">View</code> class that set a bunch of labels through a method. It must be a method because I need to give it some context.</p>
<div class="highlight highlight-source-ts notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="interface Labels {
    label1: string;
    label2: string;
    label3: string;
    label4: string;
    label5: string;
    label6: string;
    label7: string;
    label8: string;
    label9: string;
    label10: string;
}
class FormView extends View {
    label: Labels;
    labels(l: (key: string) =&gt; string): Labels { // Some abstraction take the return of this and set it to 'this.label'.
        return {
             label1: l('hello_world_1'),
             label2: l('hello_world_2'),
             label3: l('hello_world_3'),
             label4: l('hello_world_4'),
             label5: l('hello_world_5'),
             label6: l('hello_world_6'),
             label7: l('hello_world_7'),
             label8: l('hello_world_8'),
             label9: l('hello_world_9'),
             label10: l('hello_world_10'),
        }
    }

    view() {
        return  &lt;div&gt;this.label.label1&lt;/div&gt;;
    }
}"><pre class="notranslate"><span class="pl-k">interface</span> <span class="pl-smi">Labels</span> <span class="pl-kos">{</span>
    <span class="pl-c1">label1</span>: <span class="pl-smi">string</span><span class="pl-kos">;</span>
    <span class="pl-c1">label2</span>: <span class="pl-smi">string</span><span class="pl-kos">;</span>
    <span class="pl-c1">label3</span>: <span class="pl-smi">string</span><span class="pl-kos">;</span>
    <span class="pl-c1">label4</span>: <span class="pl-smi">string</span><span class="pl-kos">;</span>
    <span class="pl-c1">label5</span>: <span class="pl-smi">string</span><span class="pl-kos">;</span>
    <span class="pl-c1">label6</span>: <span class="pl-smi">string</span><span class="pl-kos">;</span>
    <span class="pl-c1">label7</span>: <span class="pl-smi">string</span><span class="pl-kos">;</span>
    <span class="pl-c1">label8</span>: <span class="pl-smi">string</span><span class="pl-kos">;</span>
    <span class="pl-c1">label9</span>: <span class="pl-smi">string</span><span class="pl-kos">;</span>
    <span class="pl-c1">label10</span>: <span class="pl-smi">string</span><span class="pl-kos">;</span>
<span class="pl-kos">}</span>
<span class="pl-k">class</span> <span class="pl-smi">FormView</span> <span class="pl-k">extends</span> <span class="pl-smi">View</span> <span class="pl-kos">{</span>
    <span class="pl-c1">label</span>: <span class="pl-smi">Labels</span><span class="pl-kos">;</span>
    <span class="pl-en">labels</span><span class="pl-kos">(</span><span class="pl-s1">l</span>: <span class="pl-kos">(</span><span class="pl-s1">key</span>: <span class="pl-smi">string</span><span class="pl-kos">)</span> <span class="pl-c1">=&gt;</span> <span class="pl-smi">string</span><span class="pl-kos">)</span>: <span class="pl-smi">Labels</span> <span class="pl-kos">{</span> <span class="pl-c">// Some abstraction take the return of this and set it to 'this.label'.</span>
        <span class="pl-k">return</span> <span class="pl-kos">{</span>
             <span class="pl-c1">label1</span>: <span class="pl-en">l</span><span class="pl-kos">(</span><span class="pl-s">'hello_world_1'</span><span class="pl-kos">)</span><span class="pl-kos">,</span>
             <span class="pl-c1">label2</span>: <span class="pl-en">l</span><span class="pl-kos">(</span><span class="pl-s">'hello_world_2'</span><span class="pl-kos">)</span><span class="pl-kos">,</span>
             <span class="pl-c1">label3</span>: <span class="pl-en">l</span><span class="pl-kos">(</span><span class="pl-s">'hello_world_3'</span><span class="pl-kos">)</span><span class="pl-kos">,</span>
             <span class="pl-c1">label4</span>: <span class="pl-en">l</span><span class="pl-kos">(</span><span class="pl-s">'hello_world_4'</span><span class="pl-kos">)</span><span class="pl-kos">,</span>
             <span class="pl-c1">label5</span>: <span class="pl-en">l</span><span class="pl-kos">(</span><span class="pl-s">'hello_world_5'</span><span class="pl-kos">)</span><span class="pl-kos">,</span>
             <span class="pl-c1">label6</span>: <span class="pl-en">l</span><span class="pl-kos">(</span><span class="pl-s">'hello_world_6'</span><span class="pl-kos">)</span><span class="pl-kos">,</span>
             <span class="pl-c1">label7</span>: <span class="pl-en">l</span><span class="pl-kos">(</span><span class="pl-s">'hello_world_7'</span><span class="pl-kos">)</span><span class="pl-kos">,</span>
             <span class="pl-c1">label8</span>: <span class="pl-en">l</span><span class="pl-kos">(</span><span class="pl-s">'hello_world_8'</span><span class="pl-kos">)</span><span class="pl-kos">,</span>
             <span class="pl-c1">label9</span>: <span class="pl-en">l</span><span class="pl-kos">(</span><span class="pl-s">'hello_world_9'</span><span class="pl-kos">)</span><span class="pl-kos">,</span>
             <span class="pl-c1">label10</span>: <span class="pl-en">l</span><span class="pl-kos">(</span><span class="pl-s">'hello_world_10'</span><span class="pl-kos">)</span><span class="pl-kos">,</span>
        <span class="pl-kos">}</span>
    <span class="pl-kos">}</span>

    <span class="pl-en">view</span><span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
        <span class="pl-k">return</span>  <span class="pl-kos">&lt;</span><span class="pl-smi">div</span><span class="pl-kos">&gt;</span><span class="pl-smi">this</span><span class="pl-kos">.</span><span class="pl-c1">label</span><span class="pl-kos">.</span><span class="pl-c1">label1</span><span class="pl-c1">&lt;</span><span class="pl-pds"><span class="pl-c1">/</span>div&gt;;</span><span class="pl-c1"></span>
    <span class="pl-kos">}</span>
<span class="pl-kos">}</span></pre></div>
<p dir="auto">As you can see above there is a heavy repeating of properties one as an interface and one as a returning data structure. And I need to do this on every view class. And there is a bunch of them.</p>
<h1 dir="auto">Solution</h1>
<p dir="auto">Contextually type type argument.</p>
<div class="highlight highlight-source-ts notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="abstract class A&lt;T&gt; {
    label: T;
    public labels(): T;
} 

class B extends A {
    labels() {
        return {
             label1: l('hello_world_1'),
             label2: l('hello_world_2'),
             label3: l('hello_world_3'),
             label4: l('hello_world_4'),
             label5: l('hello_world_5'),
             label6: l('hello_world_6'),
             label7: l('hello_world_7'),
             label8: l('hello_world_8'),
             label9: l('hello_world_9'),
             label10: l('hello_world_10'),
        }
    }

    view() {
        return  &lt;div&gt;this.label.label1&lt;/div&gt;;
    }
}"><pre class="notranslate"><span class="pl-k">abstract</span> <span class="pl-k">class</span> <span class="pl-smi">A</span><span class="pl-c1">&lt;</span><span class="pl-smi">T</span><span class="pl-c1">&gt;</span> <span class="pl-kos">{</span>
    <span class="pl-c1">label</span>: <span class="pl-smi">T</span><span class="pl-kos">;</span>
    <span class="pl-k">public</span> <span class="pl-c1">labels</span><span class="pl-kos">(</span><span class="pl-kos">)</span>: <span class="pl-smi">T</span><span class="pl-kos">;</span>
<span class="pl-kos">}</span> 

<span class="pl-k">class</span> <span class="pl-smi">B</span> <span class="pl-k">extends</span> <span class="pl-smi">A</span> <span class="pl-kos">{</span>
    <span class="pl-en">labels</span><span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
        <span class="pl-k">return</span> <span class="pl-kos">{</span>
             <span class="pl-c1">label1</span>: <span class="pl-en">l</span><span class="pl-kos">(</span><span class="pl-s">'hello_world_1'</span><span class="pl-kos">)</span><span class="pl-kos">,</span>
             <span class="pl-c1">label2</span>: <span class="pl-en">l</span><span class="pl-kos">(</span><span class="pl-s">'hello_world_2'</span><span class="pl-kos">)</span><span class="pl-kos">,</span>
             <span class="pl-c1">label3</span>: <span class="pl-en">l</span><span class="pl-kos">(</span><span class="pl-s">'hello_world_3'</span><span class="pl-kos">)</span><span class="pl-kos">,</span>
             <span class="pl-c1">label4</span>: <span class="pl-en">l</span><span class="pl-kos">(</span><span class="pl-s">'hello_world_4'</span><span class="pl-kos">)</span><span class="pl-kos">,</span>
             <span class="pl-c1">label5</span>: <span class="pl-en">l</span><span class="pl-kos">(</span><span class="pl-s">'hello_world_5'</span><span class="pl-kos">)</span><span class="pl-kos">,</span>
             <span class="pl-c1">label6</span>: <span class="pl-en">l</span><span class="pl-kos">(</span><span class="pl-s">'hello_world_6'</span><span class="pl-kos">)</span><span class="pl-kos">,</span>
             <span class="pl-c1">label7</span>: <span class="pl-en">l</span><span class="pl-kos">(</span><span class="pl-s">'hello_world_7'</span><span class="pl-kos">)</span><span class="pl-kos">,</span>
             <span class="pl-c1">label8</span>: <span class="pl-en">l</span><span class="pl-kos">(</span><span class="pl-s">'hello_world_8'</span><span class="pl-kos">)</span><span class="pl-kos">,</span>
             <span class="pl-c1">label9</span>: <span class="pl-en">l</span><span class="pl-kos">(</span><span class="pl-s">'hello_world_9'</span><span class="pl-kos">)</span><span class="pl-kos">,</span>
             <span class="pl-c1">label10</span>: <span class="pl-en">l</span><span class="pl-kos">(</span><span class="pl-s">'hello_world_10'</span><span class="pl-kos">)</span><span class="pl-kos">,</span>
        <span class="pl-kos">}</span>
    <span class="pl-kos">}</span>

    <span class="pl-en">view</span><span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
        <span class="pl-k">return</span>  <span class="pl-kos">&lt;</span><span class="pl-smi">div</span><span class="pl-kos">&gt;</span><span class="pl-smi">this</span><span class="pl-kos">.</span><span class="pl-c1">label</span><span class="pl-kos">.</span><span class="pl-c1">label1</span><span class="pl-c1">&lt;</span><span class="pl-pds"><span class="pl-c1">/</span>div&gt;;</span><span class="pl-c1"></span>
    <span class="pl-kos">}</span>
<span class="pl-kos">}</span></pre></div>
<p dir="auto">There is no repetition of <code class="notranslate">label1, label2...</code> etc above.</p>