Difference between TypeScript optional type and type | undefined
Asked Answered
R

4

13

I am struggling to understand the difference between having a field defined as string | undefined and string?

Our current code uses type definitions like this one:

class Foo {
  public bar: string | undefined;
}

When running this code through TSLint it will take notice and complain about it:

Consider using '?' syntax to declare this property instead of 'undefined' in its type.

Now the question is will using the ? syntax work exactly the same or are there subtle differences that I am missing?

class Foo {
  public bar?: string;
}

So how we are using the string | undefined type right now is in checks like this one:

if (foo.bar) {..} Will this change?

It seems the typescript documentation goes into depth about optional types but not really into how this behaves in a class context.

Rollway answered 19/11, 2018 at 9:9 Comment(0)
I
17

bar?: string is an optional property, whereas bar: string | undefined is a required one:

interface Foo { 
    bar?: string
}

interface Foo2 {
    bar: string | undefined
}

const foo: Foo = {} // OK
const foo2: Foo2 = {} // error, bar is required
const foo2: Foo2 = {bar: undefined} // OK

Regarding this case:

if (foo.bar) {..}

Both approaches are OK (including that Intellisense works in either way).

Inflatable answered 19/11, 2018 at 9:40 Comment(1)
After reading your answer I am still confused with my question So can you take a look at my question #77053775 ?Olvera
A
10

As of Typescript 4.4, you can use the exactOptionalPropertyTypes option to make optional properties even more different from type | undefined.

By default, Typescript actually treats this...

interface Person {
  name: string;
  age?: number;
}

...the same as this...

interface Person {
  name: string;
  age?: number | undefined;
}

In other words, the ? actually adds undefined to the type definition, in addition to allowing you to ignore that property. Any of these assignments is acceptable:

const tom: Person = {name: "tom", age: 53};
// This is allowed because of `?`, which adds `undefined` to the type
const john: Person = {name: "john", age: undefined};
// This is allowed because of `?`
const mary: Person = {name: "mary"};

But when using exactOptionalPropertyTypes, the second one is not allowed by an optional type:

const tom: Person = {name: "tom", age: 53};
// This is NOT allowed with just `?`. You have to explicitly add `undefined` to the type
const john: Person = {name: "john", age: undefined};
// This is allowed because of `?`
const mary: Person = {name: "mary"};

See the typescript 4.4 release notes for more information.

Antisemite answered 29/9, 2021 at 14:56 Comment(1)
I think this is a better answer than the accepted.Djakarta
M
5

bar: string | undefined: the property has to be declared and it can be either a string or undefined.

bar?: string: the property can be not declared; if it's declared see before.

Madaih answered 19/11, 2018 at 9:15 Comment(0)
L
1

Same answer as above ones, with code example

// optional property, may be skipped
type Foo = {
    bar?: string; // i.e. string | undefined, optional
};

const a: Foo = {
    bar: undefined, // ok
};

const a2: Foo = { } // also ok

const a3: Foo = {
    bar: null, // ERROR!! Must be string OR undefined
};

const a4: Foo = {
    bar: 'sup', // ok, obviously
};

// --------------------

// property is NOT optional, must be declared
type Foo2 = {
    bar: string | undefined; // REQUIRED
}

const b: Foo2 = { } // ERROR!!

const b2: Foo2 = {
    bar: undefined, // ok
};

const b3: Foo2 = {
    bar: null, // ERROR!! Must be string OR undefined
};

const b4: Foo2 = {
    bar: 'sup', // ok, obviously
};

Also there is this difference dealing with these types at runtime:

const a1 = { b: undefined }
Object.keys(a1).forEach(k => console.log(k))
// CONSOLE: b

const a2 = {}
Object.keys(a2).forEach(k => console.log(k))
// CONSOLE:
Lizliza answered 8/12, 2020 at 17:53 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.