Open4
TypeScriptの挙動メモ
ネストしてユニオンを持つ型にはnarrowingが働かない
type StringValue = {
type: 'string';
};
type NumberValue = {
type: 'number';
};
type OuterUnion = StringValue | NumberValue;
type InnerUnion = {
type: 'string' | 'number';
};
const useOuterUnion = (union: OuterUnion) => {
if (union.type === 'string') {
// unionはStringUnionにnarrowingされるので型エラーは発生しない
useString(union);
}
};
const useInnerUnion = (union: InnerUnion) => {
if (union.type === 'string') {
// union.typeはstring"にnarrowingされる
// unionはInnerUnionのままなので型エラーが発生する
useString(union);
}
};
/** 引数がStringValue型でないとき型エラーが発生する */
const useString = (string: StringValue) => {};
TypeScriptのパフォーマンスに関する公式の情報
interfaceのほうがtypeよりパフォーマンス上の利点があるなど重要な情報が載っている
変数を書き換えられないときはnarrowingした型でキャプチャされる
let a: 'string' | 'number' = 'string';
if (a === 'string') {
setTimeout(() => {
// aは'string' | 'number'型
a
}, 1000);
}
// このようにコールバックの実行前にif文のチェック内容を壊される可能性があるので
// narrowingが発生していないと思われる
a = 'number';
const b: 'string' | 'number' = 'string';
if (b === 'string') {
setTimeout(() => {
// bは'string'型
b
}, 1000);
}
readonlyフィールドはimmutableではないのでフィールドのnarrowingが引き継がれない
const obj: { value: 'string' | 'number' } = { value: 'string' };
const obj2: { readonly value: 'string' | 'number' } = obj;
if (obj2.value === 'string') {
// obj2.valueは'string'型
setTimeout(() => {
// obj2.valueは'string' | 'number'型
}, 1000);
}
// readonlyなフィールドも書き換えられる可能性がある
obj.value = 'number';