【TypeScript】作成した型の絞り込みを行う

技術的なメモです。


基本的な型の絞り込み

型の絞りこみは TypeScript でなくとも行えますが、
その絞り込みを通知することができます。

if節内部でホバーしてみると分かります。

function juice(fruit: 'apple' | 'orange' | 'grape') {
    if (fruit === 'apple') {
        // ★ fruit が apple であることが認識できる
    }
}

この恩恵を与れる簡単な利用方法です。

タグ付きユニオン型

APIの処理結果など

  • ユニオン型のそれぞれの構造が大きく変わる

場合に利用できます。

type Result = Success | Error
type Success = { data: string }
type Error = { error_message: string, data: string }

fucntion show(result: Result) {
    // Error型のチェック
    // この時点ではSuccess型の可能性があるため、Successにないプロパティの参照は許されない。
    // in を使ってプロパティが存在するかを確認する
    if ("error_message" in result) {
        // ここでError型と推論される
    }
}

in を使った構成でなく、ユニオン型の構成要素に「識別するためのタグ」をつけます。

type Result = Success | Error
type Success = { kind: 'success', data: string }
type Error = { kind: 'error', error_message: string, data: string }

fucntion show(result: Result) {
    // Error型のチェック
    // Success/Errorどちらも kind を共通してプロパティに持っているため、
    // result.kindによるアクセスが行える
    if (result.kind === 'error') {
        // ここでError型と推論される
    }
}

T | should have been removed の改善

const arr = [1,2,3,null];

arr.filter(x => x).map(x => x*2);

このコードは map 内でエラーになります。
変数 arrnumber | null 型であり filter では null を除外しているのですが、
これが認識されず引き続き number | null 型とみなされています。 そのため null との演算が行えずエラーとなります。

このように標準の組み込み関数では除外したはずの型がコンパイラは十分に認識されないことがあります。

この場合、ユーザー型ガードを利用します。

function isNotNull<T>(x: T): x is Exclude<T, null> {
    return x != null 
}

const arr = [1,2,3,null];
arr.filter(isNotNull).map(x => x*2)

自作関数 isNotNullnull の除外を宣言したことで、filter の後では null の可能性がないことを認識してくれます。


移行済(JavaScriptに毛が生えたような any まみれ)のコードで活かす機会は少ないのですが...

【TypeScript】Enumは非推奨

技術的なメモです。


結論

Enum を使ってはダメ。

ざっくりとした理由

string enum の特殊な構造

string enum は構造的部分型でなく例外的に公称型を採用している。

型安全でない

単純な Enum でなく拡大された型(e.g. number 型)となり定義外の値を参照できることがある。

そのほかに

パフォーマンスが悪いなど。

対策

ユニオンリテラル

const Kind =
  | 0
  | 1
  | 2

シンプルな記述だが、 Kind 型の絞り込みを行う場合にベタ書きになりやすい。

function showKind(k: kind) {
    if (k === 2) { // 定義値「2」の記述が散乱しやすく検索性に劣る
        ...
    }
}

keyof typeof 戦略

const mammal = {
    human: "Human",
    alpaca: "Alpaca",
    elephant: "Elephant"
} as const

type Mammal = typeof mammal[keyof typeof mammal];

mammal の値に安全にアクセスできる記法。
値を取り出すだけで大仰な記述だが、定数定義の記述変更に追従できるメリットが特に大きい。

注意

keyof typeof 戦略において、定数定義に as const を付けないと Mammalstring 型になる。

【TypeScript】定数から型を作る

技術的なメモです。


モチベーション

次のような定数定義があるとします。

const RGB = {
  red: "Red",
  green: "Green",
  blue: "Blue"
}

このとき、定数 RGB

  • キーをキーに持つ型を作る
  • 値をキーに持つ型を作る

ことを考えます。
例えば、定数 RGB の構造を利用して「RGB値」の型を定義したいなどの状況です。

これが可能であるなら、次のようなメリットがあります。

  • RGB の定義変更に応じて作成した型が追従される
  • 定数から型を安全に作成できるため、定数を作成しようとする意識が自然に芽生える

キーをキーにもつ

type kRGB = Record<RGB, number>

TypeScript組み込みの Record 型を使います。
これによりキーを参照しながら number 型を値に持つ型を作成できます。

値をキーに持つ

type vRGB = Record<typeof RGB[keyof typeof RGB], number>

オブジェクトの値に安全にアクセスする手法として obj[keyof typeof obj] があります。これを利用しています。

注意事項

値をキーに持つ場合において、定数定義に as const を指定する必要があります。
はじめに記載したままでは単なるインデックスシグニチャになります。

【CLF】vs

Price

名前 役割
AWS Pricing Calcurator 特定のAWSサービスの費用を見積もり、異なるリージョンと比較できる
AWS Budget コストと使用料の予算を設定し、対する消費量を監視する
AWS Cost Explorer 過去のAWS使用量とコストを視覚的に分析する
AWS Billing and Cost Management AWSの請求書の支払い、使用量のモニタリング、コストの計上
AWSのコストと使用状況レポート AWSのコストと使用状況に関する包括的なデータ

AWS CodeX

名前 役割
AWS CodeStar AWSでアプリケーションを迅速に開発・構築してデプロイするサービス
AWS CodePipeline コードチェンジがあった場合の構築、テスト、デプロイを自動化できる継続的デリバリーサービス
AWS CodeDeploy EC2、Fargate、Lambda、オンプレミス上のサーバーなどへのデプロイを自動化するサービス
AWS CodeCommit Gitベースのリポジトリをホストするサービス

テンプレート

名前 役割

カイ二乗分布の導出

Fact

Proof

$Y \le y \iff -\sqrt{y} \le X \le \sqrt{y}$ に注意して, $Y$ の累積分布を計算します.

ここで $\phi(u)$ は標準正規分布確率密度関数です.
この両辺を $y$ で微分すると,

となります.
(最初の変形について, 左辺は累積分布関数→確率密度関数, 右辺は微分積分学の基本定理&合成関数の合わせ技)

もう少し変形すると自由度1のカイ二乗分布となることが分かります.

DI Method

日本語では瞬間部分積分という名で知られているようですが,
こちらの名前は海外で紹介されているのであえて取り上げます.
(例題探しも豊富ですからね)


モチベーション

$\int f(x)g(x) \,dx$ の形の積分を解く場合を考えます.
ただし, $f,g$ の少なくとも一方は多項式のように $g^{(k)} \equiv 0$ となる $k$ が存在するものとします.
(以下 $g$ が上の条件を満たすものとします)

以下は素朴に部分積分を繰り替えす方法の復習です:

便宜上 $f_{+k}$ を $f$ を $k$ 回積分した原始関数とすると,
$f(x)g(x) = f_{+1}'(x) g(x)$ と置き換えて部分積分を行います.

つまり, $f$ について1回積分し, $g$ について1回微分するようになります.
これが $g^{(k)} \equiv 0$ となるまで繰り返します.

ただし部分積分特有の式変形は写し間違いや単純な計算ミスを誘発しがちです.
この記法を単純化したのが DI Method です.

DI Method

計算時に次の形式で $f$, $g$ を書き込みます:

このテーブルの行ごとを符号を含めて掛け算し, この計算結果を足し合わせます.
これが $\int f(x)g(x)\,dx$ の計算結果となります.
(大仰な記述ですが, 単に部分積分を繰り返しただけです)

利用

指数部分が $-$ の場合, すべての行の計算結果が $-$ になります.
一方で $+$ の場合では正負が交互に現れます.
(*この事実だけも検算に十分役立ちます*)

この他の利用場面

指数分布には抜群に効き目を発揮します.
その他はラプラス分布やアーラン分布あたりでしょうか。(登場頻度は格段に下がりますが)


DI Method だけではDependency Injectionがヒットします.
"integral"をつけて調べてみてください.