ホームページ  >  記事  >  ウェブフロントエンド  >  TypeScript の介入: Byzantium を使用してランタイム チェック中毒を打破する

TypeScript の介入: Byzantium を使用してランタイム チェック中毒を打破する

Barbara Streisand
Barbara Streisandオリジナル
2024-10-27 06:15:29798ブラウズ

ほら、あなたのタイプチェック中毒について話さなければなりません。はい、あなたは、認証ミドルウェアで 47 個の instanceof チェックを行っている人です。実際のコードよりも多くのテスト ケースを作成する開発者。 TypeScript を単なる派手な JSDoc コメントであるかのように扱う人。

介入

絵を描いてみましょう。今は正午、あなたは 4 杯目のコーヒーを飲みながら、運用上の問題をデバッグしています。ログには、ユーザーが何らかの方法で 15 層のランタイム検証を通過したことが示されています。 Twitter のアクティブ ユーザー数よりも多くの単体テストがあるにもかかわらず、どういうわけか、誰かが文字列があるべき場所に数値を送信できました。

「でも、それは不可能です!」あなたは泣きながら、テスト カバレッジ レポートをスクロールして、純粋な 100% を示しました。 「これ調べてみた!」

そうしましたか? 本当にしましたか?それとも、同じ小切手を 3 回書いただけですか:

  1. TypeScript インターフェイスで 1 回
  2. 再度検証ミドルウェアで
  3. 単体テストでもまた

TypeScript がすでに知っていることのテストをやめる

これは革新的なアイデアです。コンパイラを信頼したらどうでしょうか?わかります、ワイルドなコンセプト。でも聞いてください。

interface ValidRabbit {
    username: string;
    password: string;
}
interface InvalidRabbit {
    username: number;
    password: string;
}


type ValidateRabbit<Rabbit> = Assert<
    //assert that Rabbit is of type {username, password}
    Is.Type<
        User,
        {
            username: string;
            password: string;
        }
    >,
    //custom compile time exceptions
    "Trix are for kids. Provide a username and password.",
    User
>;

// Ha! Silly Rabbit...
function checkRabbit<T>(rabbit: ValidateRabbit<T>) {
    // .... protect your trix
}

declare const rabbit1: ValidRabbit;
declare const rabbit2: InvalidRabbit;

checkRabbit(rabbit1);
checkRabbit(rabbit2);
/**        ~~~~~~~~~
 *           └───── Type Exception! "...Provide a username and password"
 */

「しかし、生産はどうなるのでしょうか?」

「でも、誰かが私の API に無効な JSON を送信したらどうなるの?」という声が聞こえてきます。

まず第一に、誰があなたを傷つけたのですか?次に、API 境界を検証します。しかし、そのデータが typescript ドメインに入ったら、手放す時が来ました。コンパイラを用心棒にしましょう。

Byzantium が信頼問題の当事者にもたらすものは次のとおりです:

// Define your trust boundaries
type APIRequest<Request> = Assert<
    And<
    Is.On<Request, "body">,
    Or<Is.In<Request["method"], "POST">, Is.In<Request["method"], "PUT">>
>;,
    "Someone's being naughty with our API"
>;

// Now everything inside is type-safe
function handleRequest<R>(req: APIRequest<R>) {
    // If it compiles, it's valid
    // If it's valid, it compiles
    // This is the way
}

DevOps チームはあなたを (一度だけ) 愛します

これを想像してください: CI/CD パイプラインは数時間ではなく数分で終了します。本番環境のログには型エラーはありません。 AWS の請求書は電話番号のようには見えません。

どうやって? Byzantium では型チェックがコンパイル時に行われるためです。これ以上は不要です:

  • 型をチェックするだけの何千もの単体テストを実行する
  • 同じ型を何度もチェックすることで CPU サイクルを消費します
  • 誰かが文字列が必要であることを明確に示す関数に未定義を渡したため、午前 3 時に起床しました
// Before: Your CPU crying for help
function validateUserMiddleware(req, res, next) {
    try {
        validateId(req.params.id)        // CPU cycle
        validateBody(req.body)           // CPU cycle
        validatePermissions(req.user)    // CPU cycle
        validateToken(req.headers.auth)  // CPU cycle
        // Your CPU is now considering a career change
        next()
    } catch (e) {
        res.status(400).json({ error: e.message })
    }
}

// After: Your CPU sending you a thank you note
type ValidRequest = Assert<
    And<
        Is.On<Request, 'params.id'>,
        Is.On<Request, 'body'>,
        Is.On<Request, 'user'>,
        Is.On<Request, 'headers.auth'>
    >,
    "Invalid request shape"
>;

function handleRequest(req: ValidRequest) {
    // Just business logic, no trust issues
}

「でも、テストを書くのは大好きです!」

The TypeScript Intervention: Breaking Your Runtime Check Addiction with Byzantium
素晴らしい!実際にテストが必要なものについてはテストを作成します:

  • ビジネスロジック
  • 統合ポイント
  • ユーザーワークフロー
  • 複雑なアルゴリズム

テストの必要のないものは何か知っていますか?文字列が実際に文字列であるかどうか。その存続の危機は TypeScript に任せましょう。

リアルトーク: メリット

  1. 開発の迅速化

    • 同じ検証を 3 つの異なる方法で記述する必要はもうありません
    • 午前 3 時ではなくコンパイル時にエラーをキャッチ
    • 定型的な検証ではなく、機能に時間を費やします
  2. パフォーマンスの向上

    • 型チェックのための実行時のオーバーヘッドがゼロ
    • バンドル サイズが小さい (検証ライブラリなし)
    • CPU を幸せに、人生を幸せに
  3. セキュリティの向上

    • 型レベルの保証は回避できません
    • 「おっと、検証するのを忘れた」ということはもうありません
    • デフォルトで完全なカバレッジ
  4. DevOps の夢

    • より高速な CI/CD パイプライン
    • インフラストラクチャコストの削減
    • 生産インシデントの減少
    • SRE チームの幸福度 (結果は異なる場合があります)

はじめる

interface ValidRabbit {
    username: string;
    password: string;
}
interface InvalidRabbit {
    username: number;
    password: string;
}


type ValidateRabbit<Rabbit> = Assert<
    //assert that Rabbit is of type {username, password}
    Is.Type<
        User,
        {
            username: string;
            password: string;
        }
    >,
    //custom compile time exceptions
    "Trix are for kids. Provide a username and password.",
    User
>;

// Ha! Silly Rabbit...
function checkRabbit<T>(rabbit: ValidateRabbit<T>) {
    // .... protect your trix
}

declare const rabbit1: ValidRabbit;
declare const rabbit2: InvalidRabbit;

checkRabbit(rabbit1);
checkRabbit(rabbit2);
/**        ~~~~~~~~~
 *           └───── Type Exception! "...Provide a username and password"
 */

選択はあなた次第です

すべての実行時チェックを書き、TypeScript を JavaScript のオプションの入力であるかのように扱い、恐怖の中で生き続けることもできます。

または、2024 年に私たちに参加することもできます。そこでは、私たちはコンパイラーを信頼して、その仕事をさせます。

覚えておいてください: ランタイム型チェックを記述するたびに、どこかで TypeScript コンパイラがエラーを起こします。

結論

Byzantium は単なるライブラリではありません。型に関する信頼性の問題に対する介入です。実行時チェックを手放し、コンパイル時保証の力を活用する時が来ました。

あなたの CPU はあなたに感謝するでしょう。 DevOps チームはあなたに感謝するでしょう。ユーザーは (型関連のバグを見つけられないことで) 感謝するでしょう。

そして最も重要なことは、本番環境でタイプ エラーをデバッグする代わりに、ぐっすり眠っている午前 3 時に自分に感謝することです。


追伸それでも納得できない場合は、コードベース内に実行時の型チェックが何回あるか数えてみてください。次に、それに時給を掛けます。それは、あなたが TypeScript を信頼せずに費やしている時間です。

P.P.S.このブログ投稿の作成中にどのタイプも被害を受けませんでした。ただし、いくつかの実行時チェックは永久に廃止されました。

*P.P.P.S.貢献したい場合は、私の Github にアクセスしてリポジトリのクローンを作成してください。すべてがまだ新鮮なので、貢献する機会はたくさんあります。

ドキュメントとパッケージは JSR.io で入手可能

以上がTypeScript の介入: Byzantium を使用してランタイム チェック中毒を打破するの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。