Programming Field

[TypeScript] 型の足し算・引き算を作る(再) + TS 4.8 の機能を利用

以前 TS 4.1 で追加されたテンプレートリテラル型を用いて型の足し算・引き算を作ってみましたが、そこで作ったものには以下の欠点がありました。

1点目は型の定義方法を変えて Tuple への依存を減らすことで対応できましたが、2点目は TS 4.8 で追加予定の「More specific inference for constrained 'infer' types in template literal types」の修正を使うことで対応します。

ソースコード

メインは「Add」と「Sub」の型になります。
※ Playgroundへのリンク → TS Playground (4.8.0-dev.20220528)
※ 以下に gist.github.com にアップロードしたソースコードを埋め込んでいます。表示されない場合はこちら → https://gist.github.com/jet2jet/519216607115127889b2bf486edf21e1

使い方

以前に作ってみた Add / Sub 型と基本的に同じです。

  • ソースコードの「Sample1」~「Sample6」にあるように、Add / Sub それぞれの型にある2つの型変数(型引数)に数値リテラル型(123 など)を指定します。
  • ソースコード中の add 関数のように足し算関数を定義することで、number 型より厳密になっている数値変数同士の足し算の結果を数値リテラル型にすることができます。

制限事項など

  • 小数点以下の数値リテラルには対応していません。
  • Add / Sub はそのままでは bigint 型に対応していません。(Add や Sub にある number を bigint にすれば bigint 型に対応できます)

詳細

  • 「Add」と「Sub」はA・Bを文字列リテラル型に変換した上でそれぞれ「AddIntString」と「SubIntString」参照し、結果の文字列リテラルから number 型を取り出しています。
    • 文字列リテラルから number 型を取り出す処理で TS 4.8 の機能が入ることで、単なる number 型ではなく数値リテラル型を取り出すことができます。
  • 「AddIntString」は、数字で構成された文字列リテラルを桁ごとに Tuple に分解した上で(ParseIntStringToIntTuple)、「AddImpl」に渡して計算を行います。
  • 「AddImpl」では、AとBがそれぞれ負数かどうかチェックし、一方のみ負数であれば SubInner を、そうでなければ AddInner を使用します。
  • AddInner では、桁ごとに AddXTemp で足し算を行い、繰り上がりを考慮しつつ桁ごとの Tuple を組み立てています。
    • AddXTemp は数字と同じ長さの Tuple を用意して2つ結合し、その長さを取り出すことで足し算を実現しています。
  • SubInner では数の大小を比較して、大きい数から小さい数を引き算するようにします。(SubInner2 を使用します。)
    • SubInner2 は繰り下がりを考慮しながら桁ごとに SubXTemp で引き算を行いますが、「01」「002」などとならないように「0」を一時除外する処理を入れています。
      • SubXTemp は数字と同じ長さの Tuple について一方の Tuple が「もう一方の Tuple」+「余分な配列」となるはずのため、この「余分な配列」の長さを得ることで引き算を実現しています。
  • 「Sub」は、「Add」の中に既に減算処理が含まれているので、Bの符号を反転させて「Add」を呼び出すだけとしています。

その他・ライセンス

  • ソースコード冒頭にリンクしているライセンスにもあるように、本ソースコードのライセンスは gist jet2jet/LICENSE に従います。(2020年10月時点では0条項BSDライセンスとしており、現時点で変更の予定はありません。)
  • ソースコードに対して誤り等がありましたら、gist 上のコメント欄にてコメントをいただければと思います。(「当サイトについて」からリンクしているメールフォームからでも構いません。)

更新履歴

  • 2022/05/29 - 作成