Typescriptを使っている際、よく下記のようなシチュエーション、書き方をしたくなりますよね。
①ある変数がnull、undefinedの可能性がある
②ある変数をisNotNullメソッドにてnull, undefinedでないことをチェックする
③nullでないことが保証されたある変数を別のメソッドに渡す
④Argument of type undefined is not assignable to parameter of type xxxxのエラー
いやいや、isNotNullメソッドでundefinedでないことチェック済やんけ。。。という感じなのですがtsc的にはエラーを出してきます。
例
type Status = 'success' | 'failuer';
const messages: { [key in Status]: string } = {
success: '成功',
failuer: '失敗',
};
const isNotNull = (status: Status | undefined) => {
if (status == null) {
return false;
}
return true;
}
const getMessage = (status: Status) => {
return messages[status];
}
let st;
if (isNotNull(st)) {
console.log(getMessage(st));
// undefinedではないことをisNotNull関数でチェックしているのに、エラーとなってしまう
// Argument of type 'undefined' is not assignable to parameter of type 'Status'.
}
対処法①(Bad)
型アサーションや!を使って無理やり解決できますが、Typescriptの型システムを
台無しにしてしまうので避けたほうが良いです
type Status = 'success' | 'failuer';
const messages: { [key in Status]: string } = {
success: '成功',
failuer: '失敗',
};
const isNotNull = (status: Status | undefined) => {
if (status == null) {
return false;
}
return true;
}
const getMessage = (status: Status) => {
return messages[status];
}
let st;
if (isNotNull(st)) {
console.log(getMessage(st as any)); // 型アサーションで無理やり解決する
}
対処法②(Good)
メソッドの戻り値に型付けを行えます。
下記で、isNotNullメソッドの戻りがtrueであればundefinedでないことを明示してみます。
ただし、isNotNull自体がバグっている場合でもtrueが返却されるとその型で認識されてしまうので注意が必要です。
(ここはなんだかなーというところ)
type Status = 'success' | 'failuer';
const messages: { [key in Status]: string } = {
success: '成功',
failuer: '失敗',
};
// メソッドの戻り値で型付けを行う(status is Statusの部分)
// trueが返った場合、statusはStatus型であるという表現になる
const isNotNull = (status: Status | undefined): status is Status => {
if (status == null) {
return false;
}
return true;
}
const getMessage = (status: Status) => {
return messages[status];
}
let st;
// isNotNullがtrueの場合、statusはStatus型であるとtscが認識するため、
// コンパイルエラーは出ない
if (isNotNull(st)) {
console.log(getMessage(st));
}
// falseの場合はもちろんエラー出る
if (!isNotNull) {
console.log(getMessage(st));
// Argument of type 'undefined' is not assignable to parameter of type 'Status'.
}
私のレベルの問題かもしれませんが初めて知った時感動しました。
この手のエラーは困ることあるけど、ググり方もわからないし調べづらいので
お役に立てば幸いです。