EDIT: Important Note As Quentin C pointed out in the below comment, the behavior listed here is only when strict null checking is enabled: "strictNullChecks": true in tsconfig.json.
The types null and undefined are handled as separate types. The optional type is special, also allowing arguments to be left out of function calls.
1. Without a union or optional, nothing except the type itself is allowed.
function foo(bar: string) { console.info(bar); } foo("Hello World!"); // OK foo(null); // Error foo(undefined); // Error foo() // Error
2. To additionally allow null, a union with null can be made.
function foo(bar: string | null) { console.info(bar); } foo("Hello World!"); // OK foo(null); // OK foo(undefined); // Error foo() // Error
3. Allowing undefined works similarly. Note that the argument cannot be left out or null.
function foo(bar: string | undefined) { console.info(bar); } foo("Hello World!"); // OK foo(null); // Error foo(undefined); // OK foo() // Error
4. You can also allow both, but the argument MUST still be given.
function foo(bar: string | null | undefined) { console.info(bar); } foo("Hello World!"); // OK foo(null); // OK foo(undefined); // OK foo() // Error
5. With optional you can leave the argument out, or pass undefined, BUT NOT null.
function foo(bar?: string) { console.info(bar); } foo("Hello World!"); // OK foo(null); // Error foo(undefined); // OK foo() // OK
6. To allow all three special cases, optional and null can be combined.
function foo(bar?: string | null) { console.info(bar); } foo("Hello World!"); // OK foo(null); // OK foo(undefined); // OK foo() // OK
Also, optional is only usable in parameter or other type declarations, such as interfaces, not on regular variables. As it would make no sense to leave out the value of a variable when assigning to it.
Thus,
let d?: string;
would make no sense and results in a compilation error.