编辑: 固定"测试"到"约束"在接口
我无法理解通用约束在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:输入&#39;(s:string,c:TestWithData)=&gt;空隙&#39;不能分配类型&#39; SomeType&#39;。 参数类型&#39; c&#39;和&#39;行动&#39;是不相容的。 输入&#39; A&#39;不能分配给&#39; TestWithData&#39;。 输入&#39; SomeConstraint&#39;不能分配给&#39; TestWithData&#39;。 财产&#39;测试&#39;类型&#39; SomeConstraint&#39;
中缺少我缺少什么?
被修改
正如我所说,我在redux类型中找到了这个(类似的)构造。你可以找到这个定义(redux&#34; 3.7.2&#34;):
export type Reducer<S> = <A extends Action>(state: S, action: A) => S;
现在,当你想要定义你的reducer你需要提供状态和动作时,我会跳过状态部分,所以,我可以写这样的动作:
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) => {...}
答案 0 :(得分:1)
对于您给出的示例,我不认为泛型+约束是我定义类型的方式(它可能将是我在标称类型系统中的方式,但不是在结构类型系统中。)
type SomeType<T> = <A extends SomeConstraint>(item: T, action: A) => void;
如果您说&#34;该项目必须具有constraint
属性,您可以使用更简单的方式获取此项:
type SomeType<T> = (item: T, action: SomeConstraint) => void;
结构化打字负责其余部分。
在实际实现中,您可以使用与SomeType
定义兼容的任何类型......
const actualImplementation: SomeType<string> = (item: string, action: Test): void => {
}
以下是完整版,请记住Test
界面需要constraint
属性,或者扩展SomeConstraint
界面,否则您将错过基本使类型兼容的属性。
interface SomeConstraint {
constraint: any
}
type SomeType<T> = (item: T, action: SomeConstraint) => void;
interface Test extends SomeConstraint{ test: string }
const actualImplementation: SomeType<string> = (item: string, action: Test): void => {
}
const a: Test = { constraint: '', test: '' };
actualImplementation('', a);
上述示例中的关键点是实际实现可以是您的Test
类型,没有错误。