2017-08-24 15 views
2

関数の最後にneverを代入(またはアサート)することは、コンパイル時に徹底的なチェックを強制するためにTypescriptで使用される手法です。明示的な文字列のない徹底チェック

コンパイラがこれを検出するには、neverの代入/アサーションの前に関数が確実に戻るかどうかを調べるために、明示的な文字列が必要です。

Object.freezeの型付きバリエーションを導入することは可能でしょうか?オブジェクトリテラルだけで動作し、さらにチェーンを上回るので、次のようなことができますか?

さらに、Action.type(この例では)ののキーが自動的に作成されるインターフェイスを作成する方法はありますか?その場合、actionMapをそのインタフェースとして宣言するだけでコンパイル時にチェックを強制することができます。

どちらも同じ問題の解決策です。差別化された共用体しか与えられていないので、コンパイル時に関数内の明示的な文字列を使用する必要はありません。

interface Increment { 
    type: 'increment' 
} 

interface Decrement { 
    type: 'decrement' 
} 

type Action = Increment | Decrement 

const inc: Increment = { type: 'increment' }; 
const dec: Decrement = { type: 'decrement' }; 

//this would be a typescript variation 
const actionMap = Object.freeze({ 
    [inc.type]: n => n + 1, 
    [dec.type]: n => n-1 
}); 


function doAction(action: Action, val: number): number { 

    if(actionMap[action.type]) { 
     return actionMap[action.type](val); 
    } 

    //this would error at compile time if the above checked failed 
    const _exhaustiveCheck: never = action; 
} 

console.log(doAction(inc, 1)); 
console.log(doAction(dec, 1)); 
+0

actionMapが、識別された共用体 'Action'内のすべての' type'値の値を持っているかどうかチェックしたいとします。これは正しいです? –

+0

うん!そのとおり :) – davidkomer

答えて

3

それが判別組合における各ケースの値を持っていることを保証マップを作るために、かなりまっすぐ進む方法があります。その鍵のタイプが識別された共用体識別子になるように設定するだけです。

type ActionMap = { 
    [P in Action["type"]]: (val:number)=>number 
}; 

あなたは、このようになります。このインタフェースを実装することができます

var map: ActionMap = { 
    decrement: n => n - 1, 
    increment: n=> n + 1 
} 

編集:いじりの束の後、私はあなたをないことができますはるかに汎用性と強力な解決策を見つけました識別されたユニオン値のキーだけを入力するだけでなく、ペイロードを入力することもできます。

最初:キー:タイプのペアの形式でユニオンを定義します。そのマップからアクション識別型の共用体を作成します。第二に

type Actions = { 
    "increment": { incrementValue: number } 
    "decrement": { decrementValue: number } 
} 

(私はこれがとにかく読むためにきれいだと思います)。これは世界でも最も明白なコードではありません。ActionsMapの各キー値のペアは、タイプ値{type:key}を追加して新しいタイプを作成し、これらのタイプを合計して差別化ユニオンを作成します。

type Action = { 
    [P in keyof Actions]: { type: P } & ActionsMap[P] 
}[keyof Actions]; 

サード

フォース
type ActionsMap = { 
    [P in keyof Actions]: (val:number,action:Actions[P])=>number 
} 

あなたのマップの種類を作成します。あなたの完全にタイプセーフアクション/減速マップをお楽しみください!

const map:ActionsMap = { 
    decrement: (val, action) => val + action.decrementValue, 
    increment: (val, action) => val + action.incrementValue, 
} 

公正な警告。これは、タイスクリプト定義ができることに限界を押しつけ、次のバージョンで変更するために、いくつかのタイスクリプトのフリンジ動作に頼ることで個人的には噛まれました。

関連する問題