TypesScriptチップ:ブランドタイプを持つより安全な機能.


このような機能があると想像してください.
interface Post {
  id: number
  title: string
}

export function getPosts(page: number): Post[] {
  // perform some query to return posts from a database
  // ...
  // ...
  return []
}
getPosts Aを受け入れるpage 引数とデータソースから投稿を取得します.
さて、getPosts このように使用されますか?
const posts = getPosts(-1);
ページ番号が負であることができないので、明らかにそれは不正確です.単純な解決策は、次のように行を追加します.
if(page < 0) throw Error('Page must be a positive number')`
しかし、負の数で関数をコールしようとすると、型エラーを受け取ると良いでしょう.
ここの問題は、そのタイプnumber 関数には一般的です.number 任意の数をすることができます我々はちょうど肯定的な数を期待している.
そのための型別名を作成できます:
type PositiveNumber = number;
私たちのコードをより読みやすくしますが、単純なエイリアスを使用することは問題を解決しません.私たちはまだ引数として任意の数を渡すことができるのでgetPosts() .
これは、ブランド型を作成するときです.

ブランドタイプ


基底型が一般的な場合、このパターンを使用できます.
type PositiveNumber = number & { __type: 'PositiveNumber' };
ここでは、基本型の間の交差点を使用しますnumber ) そして、__type このプライベートプロパティは、その型を保持し、number .
以下の関数を書き換えることができます.
type PositiveNumber = number & { __type: 'PositiveNumber' };

export function getPosts(page: PositiveNumber): Post[] {
  // ...
  return []
}
今、我々が前にそれを呼ぶようにしようとするならば、我々は我々が予想する誤りを受けるつもりです.
const posts = getPosts(-1); 
// ^^^ Argument of type 'number' is not assignable to parameter of type 'PositiveNumber'.
有効な数字を試してみましょう.
const posts = getPosts(2); 
// ^^^ Argument of type 'number' is not assignable to parameter of type 'PositiveNumber'.
うーん、それは意味をなさない🤔, 確かだ2 は正の数です.
我々はまだ同じエラーを受けていますnumber , ないPositiveNumber . 息子Weeは、私たちがPositiveNumber 使用as キーワード.
const posts = getPosts(2 as PositiveNumber); 
それはエラーを取り除くでしょう.
今、私たちには、それが正の数かどうかわからない変数があるならば、どうですか?
const { page } = incomingRequest.body;  
// here, page could be a positive or a negative number, so we can't use the `as` keyword because we can't be sure of what is the actual value;

const posts = getPosts(page); 
これを解決するために、我々はページが実際であると主張するassertion関数を使用することができますPositiveNumber
function assertsPositiveNumber(value: number): asserts value is PositiveNumber {
  if(value < 0) throw new Error('Value must be a positive number');
}
今この主張で、我々はpage は正の数である.
const { page } = incomingRequest.body;  

assertsPositiveNumber(page);

const posts = getPosts(page); // at this point TypeScript know that `page` its a PositiveNumber
あなたがこの先端が好きならば♥

更なる読書

  • Assertion Functions
  • Branding and Type-Tagging