Assertion signaturesで“object is possibly null”を回避する – TypeScript

変数がnullの可能性がある場合、TypeScriptは“object is possibly null”エラーを表示します。

例えば以下のような、文字列中に含まれる数字の個数を数えるgetNumberCount関数を見てみます。

function getNumberCount(format:string){
  const num = format.match(/\d/g); // num:RegExpMatchArray|null
  return num.length;
//       ~~~~~~~~~~~ Object is possibly 'null'
}

文字列中に数字が含まれない(正規表現に一致しない)場合、matchメソッドはnullを返します。

ただし変数numはnullの可能性があるため、TypeScriptは”Object is possibly ‘null”エラーを表示します。

条件文で回避した場合の問題点

この場合、処理上nullを許容しないのであれば、処理を開始する前にnullかどうかをチェック(アサーション)してエラーを回避することができます。

function getNumberCount(format:string){
  let num = format.match(/\d/g);
  if(num === null) throw new Error("It is null"); // アサーション
  return num.length;
//       ~~~~~~~~~~~ Object is possibly 'null'は表示されなくなる
}

しかし、このアサーションを関数化してしまうと、再び“object is possibly null”が出現してしまうのです。

function matchAssert<T>(num:T){
  if(num === null) throw new Error("It is null");
}

function getNumberCount(format:string){
  let num = format.match(/\d/g);
  matchAssert(num);
  return num.length;
//       ~~~~~~~~~~~ Object is possibly 'null'が再び表示される。
}

これを回避するにはAssertion sigunaturesを使用します。

Assertion signaturesを使ったアサーションの関数化

Assertion signatures(Assertion Function)はTypeScript v3.7から搭載された機能です。

関数の返り値の型として “asserts 引数名 is 型名” を指定します。

function matchAssert<T>(num:T): asserts num is NonNullable<T>{
//                              ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Assertion signatures
  if(num === null) throw new Error("It is null");
}

function getNumberCount(format:string){
  let num = format.match(/\d/g);
  matchAssert(num);
  return num.length;
//       ~~~~~~~~~~~ Object is possibly 'null'は表示されなくなる
}

この場合、引数numがNullではない(num is NonNullable)ことをアサーションは伝えてくれます。もしnullであれば、throw new Errorで例外が返ります。

結果、”Object is possibly ‘null'”は表示されなくなります。

条件文を使ったアサーション

アサーション関数の返り値の型として “asserts 条件” としても同様の結果を得ることができます。

function matchAssert(condition:any): asserts condition {
  if(!condition) throw new Error("Not match condition");
}

function getNumberCount(format:string){
  let num = format.match(/\d/g);
  matchAssert(num !== null);  //条件文を指定
  return num.length;
//       ~~~~~~~~~~~ Object is possibly 'null'は表示されなくなる
}

アサーションの引数に条件文を指定して、条件を満たしたかどうかをアサーション関数は伝えてくれます。

 

Assertion signaturesを使うことでより安全なコードを構築することができるようになります。

Related Posts