25

Is there a way to specify type-safe optional members in Typescript classes?

That is, something like...

class Foo {
    a?: string;
    b?: string;
    c: number;
}

....

foo = new Foo();
...
if (foo.a !== undefined) { ... (access foo.a in a type-safe string manner) ... }

In case you are familiar with OCaml/F#, I am looking for something like 'string option'.

angularJsNewbie
  • 495
  • 2
  • 8
  • 14

4 Answers4

23

The following works in TypeScript 3.x:

class Foo {
  a?: string;
  b?: string;
  c: number = 123;
}

Note that you need to initialise any members that are not optional (either inline as shown or in the constructor).

basarat
  • 261,912
  • 58
  • 460
  • 511
  • 4
    Is there any way to avoid optional properties being defined at all? (`{a: 'asdf', b: 'nada' }` instead of `{a: 'asdf', b: 'nada', c: undefined }` – Aides Apr 07 '16 at 14:20
  • Also I get `Supplied characters do not match any signature of call target` on TypeScript Playground and in VS [see playground](https://www.typescriptlang.org/play/#src=class%20Test%20%7B%0D%0A%20%20%20%20constructor(a%3A%20string%2C%20b%3A%20string%2C%20c%3A%20string)%0D%0A%09%7B%0D%0A%09%09%0D%0A%09%7D%0D%0A%7D%0D%0A%0D%0Avar%20test%20%3D%20new%20Test('foo'%2C%20'bar')%3B) – Aides Apr 07 '16 at 14:30
  • This answer is outdated or at least promote thing that doesn't work by default since TypeScript 2.7. – Zbigniew Zagórski Mar 15 '18 at 09:05
  • 2
    This answer is outdated or at least promote thing that doesn't work by default since TypeScript 2.7. Since TS 2.7 you would get `Property 'c' has no initializer and is not definitely assigned in the constructor.` Which is correct answer to your code that states that `Foo#c` must be defined but it is not safety initialized. – Zbigniew Zagórski Mar 15 '18 at 09:15
  • The answer has been updated and works with the latest TypeScript versions – basarat Sep 20 '20 at 23:31
15

Optional class properties was added as a feature in Typescript 2.0.

In this example, property b is optional:

class Bar {
  a: number;
  b?: number;
}

Typescript 2.0 release notes - Optional class properties

Fredrik_Borgstrom
  • 2,504
  • 25
  • 32
  • 1
    Whilst this may theoretically answer the question, [it would be preferable](//meta.stackoverflow.com/q/8259) to include the essential parts of the answer here, and provide the link for reference. – jhpratt Nov 20 '18 at 04:04
  • Revised according to your feedback :) – Fredrik_Borgstrom Nov 20 '18 at 15:10
  • Interesting. I'm using TS 4 and it gives me unexpected token error if I add ? in a class definition. Interface seems to allow it tough. – konrad Apr 07 '21 at 04:08
12

In some use cases you can accomplish it with Parameter properties:

class Test {
    constructor(public a: string, public b: string, public c?: string)
    {
    }
}

var test = new Test('foo', 'bar');

playground

Distagon
  • 1,018
  • 11
  • 14
2

Optional properties and methods can now be declared in classes, similar to what is already permitted in interfaces:

class Bar {
    a: number;
    b?: number;
    f() {
        return 1;
    }
    g?(): number;  // Body of optional method can be omitted
    h?() {
        return 2;
    }
}

When compiled in --strictNullChecks mode, optional properties and methods automatically have undefined included in their type. Thus, the b property above is of type number | undefined and the g method above is of type (() => number) | undefined. Type guards can be used to strip away the undefined part of the type:

function test(x: Bar) {
    x.a;  // number
    x.b;  // number | undefined
    x.f;  // () => number
    x.g;  // (() => number) | undefined
    let f1 = x.f();            // number
    let g1 = x.g && x.g();     // number | undefined
    let g2 = x.g ? x.g() : 0;  // number
}

Optional class properties

Mentor
  • 3,058
  • 1
  • 22
  • 27