2017-07-12 15 views
2

Reduxの場合(特にこの問題はReduxとは関係ありません)リデューサーが使用するアクションの名前が必要ですが、名前とアクション減速機で使用される。だから私はこのコードを書いた:私は例をしようとすると、文字列型パラメータが強制されていない

interface TypedAction<N> { 
    type: N; 
} 

type TypedReducer<S, A extends TypedAction<any>> = (state: S, action: A) => S; 

function addReducer<S, R extends TypedReducer<S, A>, A extends TypedAction<N>, N>(initialState: S, actionName: N, reducer: R): {} { 
    // doesn't really matter what is returned here 
    // the point is I need the actionName during run time 
    // but want it to correspond with the reducer's action's name at compile time 
    return { 
    [actionName.toString()]: reducer 
    }; 
} 

は、しかし:

interface MyAction extends TypedAction<'MyAction'> { 
    foo: string; 
} 

const myActionReducer: TypedReducer<number, MyAction> = (state: number, action: MyAction) => state+1; 

addReducer(1, "foo", myActionReducer); // should give a compile error, because "foo" and is not of type "MyAction" 

はなぜ活字体は"foo""MyAction"であることを強制しませんか?

+0

すべての 'addReducer'引数をまとめて考えると、' foo "というユニオン型として推論されたNを持つすべての制約を満たすことができます。 "MyAction"。なぜTypeScriptは '' foo ''から' 'foo' 'の型を広げるのですか? "MyAction"?おそらく、他の現実のコードをコンパイルして、何人かの人がエラーなしでコンパイルしなければならないと考えたからでしょう。 'N'が(単数の)文字列型でなければならないという制約を加える方法はありますか?私は知らない。 – artem

+0

私の同僚は実際にそれを理解しました。彼は答えを掲示するでしょう。 'TypedAction'と' addReducer' TypeScriptのNの定義の後ろに 'extends string'を置くと、突然期待どおりに動作します。私はなぜか分からない。 –

答えて

1
interface TypedAction<T extends string> { 
    type: T; 
} 

type TypedReducer<S, A extends TypedAction<any>> = (state: S, action: A) => S; 

interface MyAction extends TypedAction<"MyAction"> { 
    foo: number; 
} 

type ActionTypeAndReducer<S, A extends TypedAction<any>> = { 
    [type: string]: TypedReducer<S, A> 
}; 

function pair<ActionType extends string, 
       A extends TypedAction<ActionType>, 
       S>(type: ActionType, reducer: TypedReducer<S, A>): ActionTypeAndReducer<S, A> { 
    return { 
    [type as string]: reducer 
    }; 
} 

const myReducer: TypedReducer<any, MyAction> = (state: any, action: MyAction) => {}; 
pair("MyAction2", myReducer); 

これは、予想される動作を生成します。

error TS2345: 
    Argument of type 'TypedReducer<any, MyAction>' is not assignable to parameter 
    of type 'TypedReducer<any, TypedAction<"MyAction2">>'. 

    Types of parameters 'action' and 'action' are incompatible.                               
    Type 'TypedAction<"MyAction2">' is not assignable to type 'MyAction'.                            
    Property 'foo' is missing in type 'TypedAction<"MyAction2">'.                             

アクションとレデューサーの両方を組み合わせた機能がこれをチェックしてペア機能を構築したと思っていました。 型は問題ありませんでしたが、コンパイラはtype argumentが返されたオブジェクトのキーであるため、stringまたはnumberでなければならないと訴えていました。私はActionType拡張文字列を作って、残りはうまくいきました。

関連する問題