编辑:在接口中将“test”更正为“constraint”
我对Typescript中的通用约束条件不太理解。我正在使用React/Redux,其中您可以找到类似于以下构造的内容:
interface SomeConstraint { constraint: any }
type SomeType<T> = <A extends SomeConstraint>(item: T, action: A) => void;
正如您所见,这是一个带有通用参数和一些约束条件的函数定义。现在,当我想要使用它时,可以编写以下内容:
interface Test { constraint: string }
const some : SomeType<string> = (s: string, c: Test ) => {}
这很好用,但是当我想要扩展测试接口(让我们称其为TestWithData)时:
interface TestWithData { constraint: string, payload: any }
const some : SomeType<string> = (s: string, c: TestWithData ) => {}
我遇到了编译时错误:
错误 TS2322:类型“(s: string, c: TestWithData) => void”不能赋值给类型“SomeType”。参数类型“c”和“action”的类型不兼容。类型“A”不能赋值给类型“TestWithData”。类型“SomeConstraint”中缺少属性“test”。
我错过了什么?
编辑:
正如我所说,我在redux类型定义中发现了这个(类似的)结构。您可以在以下定义中找到此定义(redux“3.7.2”):
export type Reducer<S> = <A extends Action>(state: S, action: A) => S;
现在,当您想定义您的reducer时,需要提供state和action,我将跳过state部分,因此,可以将action写成如下形式:
interface MyAction { type: "MY_ACTION" }
创建reducer很容易:
const reducer: Reducer<MyState> = (state: MyState, action: MyAction) => {...}
如果我将额外的数据添加到MyAction中,代码可以通过编译:
interface MyAction {
type: "MY_ACTION";
payload: any
}
如果出现上述错误,编译将失败。我本以为它会通过。那么这个限制的目的是什么呢?是告诉编译器我们期望完全相同的类型(在结构上),没有更多或更少吗?我认为这是一个非常有限的用例,我希望类型推断能够选择类型,检查其结构兼容性并保留类型签名。类似于这样但不需要指定类型参数:
export type Reducer<S, A extends Action> = (state: S, action: A) => S;
现在,类型签名已经被保留,但是在声明变量时需要指定实际参数类型(与状态声明相同):
const reducer: Reducer<MyState, MyAction> = (state: MyState, action: MyAction) => {...}