それぞれundefined
とnull
型が用意されてます。
const foo: undefined = undefined;
const bar: null = null;
もし、string | undefined
のようなUnionの場合、if構文などで絞り込むことができます。
const foo: string | undefined = '';
if (foo !== void 0) {
foo; // const foo: string;
}
Optional Chaining
TypeScriipt@^3.7 からundefined
かもしれないオブジェクトのプロパティへのアクセスを簡易に記述できるようになりました。
それ以前までは以下のような型の時、
interface MyObject {
foo?: {
bar?: {
baz(): void;
};
};
}
プロパティbaz
へ安全にアクセスしたいなら以下のようにする必要がありました。
const obj: MyObject = {} as MyObject;
if (
obj.foo !== void 0 &&
obj.foo.bar !== void 0
) {
obj.foo.bar.baz();
}
@^3.7 からは以下のように書くことができます。
obj.foo?.bar?.baz();
?.
という書き方でプロパティにアクセスすることで、値が対象のプロパティがundefined
やnull
の場合はundefined
を返し、そうでない場合は対象のプロパティ値を返すようになります。つまり、途中にundefined
やnull
があればundefined
、そうでなければ期待した結果が返ります。
配列と Optional Chaining
値がundefined
または何かの配列という場合も Optional Chaining が使えます。それには[ ]
の前に?.
を付けます。
const obj: { values?: { foo: string }[] } = {value: []};
obj.values?.[10]?.foo
obj.value
とobj.value[10]
がundefined
じゃない場合に、そのfoo
値へアクセスします。
Nullish Coalescing
TypeScriipt@^3.7 から対象の値がundefined
かnull
の時用のフォールバック値を設定する為の構文が追加されました。これはundeefinedかnullかもしれない値 ?? フォールバック値
のように??
を間に記述します。undefined
やnull
でない場合はそのままその値が使われます。
例えば以下のfn
は渡したプリミティブ値をそのまま返してくれるものです。
const fn = <
Str extends string,
Num extends number
>(obj: {
str?: Str;
num?: Num;
}) => {
const str = obj.str ?? ('str' as const);
const num = obj.num ?? (123 as const);
return { str, num };
};
const result = fn({
str: '' as const,
num: 0 as const
});
// const result: {
// str: "" | "str";
// num: 0 | 123;
// }
console.log(result);
// {str: "", num: 0}
古くからある||
を使うと''
や0
はfalsy(false
として扱われる)値なので{str: "str", num: 123}
という値が返るようになるという違いがあります。
組み合わせる
Optional Chaining は値が空の時必ずundefined
を返すため、空の時のフォールバック値を設定できる Nullish Coalescing との相性が良いです。
これは深いネストを持つオブジェクトにデフォルト値を設定するのに便利です。
type Obj = { foo?: { bar?: { baz: string } } };
const expectToReturnDefault: Obj = {};
console.log(
expectToReturnDefault.foo?.bar?.baz ?? "default"
);
// 'default'
const expectToReturnBazValue: Obj = {
foo: { bar: { baz: "baz" } }
};
console.log(
expectToReturnBazValue.foo?.bar?.baz ?? "default"
);
// 'baz'