TypeScript扩展了不编译的类型代码

时间:2018-03-03 12:58:10

标签: typescript

我理解以下打字稿错误的内容虽然我不明白为什么,因为A类型正在扩展IReduxAction并且在其他地方指定extends IReduxAction

这里的任何帮助都会很棒。

这是错误

Type '{ ACTION_NAME: IReducer<ISt, IAction<"hello", string>>; }' is not assignable to type 'TCaseFunctions<ISt>'.
  Property 'ACTION_NAME' is incompatible with index signature.
    Type 'IReducer<ISt, IAction<"hello", string>>' is not assignable to type '<A extends IReduxAction>(state: Readonly<ISt>, action: A) => ISt'.
      Types of parameters 'action' and 'action' are incompatible.
        Type 'A' is not assignable to type 'IAction<"hello", string>'.
          Type 'IReduxAction' is not assignable to type 'IAction<"hello", string>'.
            Property 'payload' is missing in type 'IReduxAction'.

这是代码。您可以将其直接粘贴到https://www.typescriptlang.org/play/index.html

的游乐场
export interface IReduxAction {
  type: any
}

export interface IGenericAction<T, P, M> extends IReduxAction {
  type: T
  payload: P
  meta?: M
}

export interface IAction<T, P> extends IGenericAction<T, P, any> {}

export type IReducer<S, A extends IReduxAction> =
  (state: Readonly<S>, action: A) => S

export type TCaseFunctions<S> = {
  [action: string]: <A extends IReduxAction>(state: Readonly<S>, action: A) => S
}

interface ISt { a: string }

type MyAction = IAction<'hello', string>
const basicAction: IReduxAction = {
  type: 'foo'
}

const reducer: IReducer<ISt, MyAction> = (state, action) => state
const caseFunctions: TCaseFunctions<ISt> = {
  ACTION_NAME: reducer
}
const rootReducer = createReducer<ISt>(caseFunctions)
// rootReducer(state, { type: 'hello', payload: 'foobar' })

1 个答案:

答案 0 :(得分:0)

TCaseFunction被定义为具有通用函数签名,因此在调用时,可以传入任何操作:

caseFunction({} as ISt, {} as MyAction)
caseFunction({} as ISt, {} as MyOtherAction)

您尝试分配给caseFunction的功能不是通用的,它需要采取特定操作(MyAction),因此它不尊重TCaseFunction定义的合同。

您可以将签名的通用参数添加到TCaseFunction,然后事情会按预期工作:

export type TCaseFunction<S, A> = (state: Readonly<S>, action: A) => S 
const caseFunction: TCaseFunction<ISt, MyAction> = reducer

修改

关于泛型函数与非泛型函数不兼容的更多细节。请考虑以下示例:

type genericFunction = <A>(param: A) => A;

let ok:genericFunction = function <A>( param: A) { return param};
// We can pass to the function any type A
ok(1); // be it int
ok(""); // or string 

let notOk:genericFunction = function (param: string ){ return param.substr(1);}
// The above assignment is not allowed because the signature for genericFunction mandates that it be able to handle any A not just a specific A
// genericFunction  allows either of these:
notOk(""); // We can pass a string, as the implementation expects
notOk(1); // but we can pass an int, which the implementation would not know how to process

<强> EDIT2

在你的情况下,你似乎并不真正关心A是什么,只是它是一个动作,你可以使用以下定义taht将强制所有成员成为第二个参数为任何IReduxAction的函数:

export type TCaseFunctions<S> = {
    [action: string]: (state: Readonly<S>, action: IReduxAction) => S;
}