til :入力スクリプトでHTTPタイプのヘッダを取得する



ゴール
私はバックエンドフレームワークの開発者です.これはタイプスクリプトで書かれています.欲しいです
  • 実際のリクエストオブジェクトを隠すhttp.IncomingMessage ) 私のユーザーから
  • まだリクエストのHTTPヘッダへのアクセスをユーザに提供します(http.IncomingHttpHeaders ).
  • IntelliSense(自動補完)を提供するので、ヘッダーの人々を使用したい見つけることが容易です.
  • ヘッダに型がないことをコンパイル時にチェックします.
  • ヘッダーを使用することができます私のユーザーを制限しないでくださいので、ヘッダーのリストは、そのサービスから拡張可能である必要があります.
  • それはすべて可能です.

    実装
    考慮するhttp.IncomingHttpHeaders インタフェース
    interface IncomingHttpHeaders {
        'accept-patch'?: string;
        'accept-ranges'?: string;
        'accept'?: string;
        
        'warning'?: string;
        'www-authenticate'?: string;
        [header: string]: string | string[] | undefined;
    }
    
    ヘッダ名がハードコードされている場合の問題点:
  • はそのリストを拡張する方法を提供しません.
  • すべての型安全性が窓から出ることを意味するインデックス署名を提供します.
  • それで、私のユーザーから実際の要求を隠すために、私はクラスと呼ばれるクラスを持っていますContext そして、各リクエストに対してハンドラのインスタンスを渡します:
    export class Context {
        constructor(private req: http.IncomingMessage) { }
        
        getHeader(name: ?) {
            return req.headers[name];
        }
    }
    
    
    私たちがしたいことは、代わりにいくつかの種類のタイプを導入することです? それで、それはそれらからのそれらのヘッダーだけを許しますhttp.IncomingHttpHeaders これはハードコード化されています.
    また、このリストを簡単に拡張することができます.

    問題1
    簡単に使えませんtype StandardHeaders = keyof http.IncomingHtppHeaders インタフェースがインデックス署名を持っているのでStandardHeaders 自動補完とコンパイル時間のチェックが動作しないように何かを受け入れる.
    解決-インターフェイスからインデックス署名を削除します.バージョン4.1以降では、キーの再マッピングとタイプスクリプト2.8と新しい条件付きの型があります.ここでは4.1バージョンのみを提供します.
    
    type StandardHeaders = {
        // copy every declared property from http.IncomingHttpHeaders
        // but remove index signatures
        [K in keyof http.IncomingHttpHeaders as string extends K
            ? never
            : number extends K
            ? never
            : K]: http.IncomingHttpHeaders[K];
    };
    
    
    それは私たちのコピーを与えるhttp.IncomingHttpHeaders インデックス署名を削除しました.
    それは事実に基づいている‘a’ extends string is true でもstring extends ’a’ is false . 同じnumber .
    今すぐにできます.
    type StandardHeader = keyof StandardHeaders;
    
    それはVSCODEが考えるものですStandardHeader :

    既知のヘッダのみのnice型リテラル.接続しましょうgetHeader(name: StandardHeader) 試してみてください.

    自動補完作業とコンパイルは中断します.


    問題2.
    我々はフレームワークです、このセットのヘッダーはかなり狭いので、我々は人々にそれを拡張する能力を与える必要があります.
    これは、前のものを解決するのがより簡単です.を作りましょうContext ジェネリックといくつかのものを追加します.
  • 一般的な文字列型リテラルを制限する
  • 賢明なデフォルトを提供する
  • export class Context<TCustomHeader extends string = StandardHeader> {
        constructor(private req: http.IncomingMessage) { }
        
        getHeader(name: StandardHeader | TCustomHeader) {
            return req.headers[name];
        }
        
    }
    
    では、以下のように書くことができます.
    const ctx = new Context<'X-Foo' | 'X-Bar'>(...);
    const foo = ctx.getHeader('X-Foo');
    const bar = ctx.getHeader('X-Bar');
    
    そして、これらのヘッダを自動補完します.

    コンパイル時にチェックを入れます.


    更なる改善
    フレームワークなので、ユーザーはContext クラス自体、我々はそれらを配っている.その代わりに、我々はクラスを導入しなければなりませんContextHeaders 置換getHeader(header: StandardHeader) ジェネリックメソッドheaders< TCustomHeader extends string = StandardHeader>: ContextHeaders<StandardHeader | TCustomHeader>これは読者=のための運動として残されている).