字符串文字类型参数未强制执行

时间:2017-07-12 15:37:29

标签: typescript

使用Redux(这个问题与Redux没有任何关系)我希望得到一个reducer使用的动作的名称,但我想确保reducer中使用的名称和动作对应。所以我写了这段代码:

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"

为什么Typescript不强制"foo"应该是"MyAction"

1 个答案:

答案 0 :(得分: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">'.                                                                                                                 

我认为结合了action和reducer的函数可以检查这个,所以我构建了pair函数。 类型还可以,但编译器抱怨说type argument必须是stringnumber,因为它是返回对象中的一个键。所以我制作了ActionType扩展字符串,然后剩下的就好了。