2017-10-04 124 views
0

通用约束编辑: 固定的“测试”在我无法理解泛型约束是如何在打字稿工作接口打字稿的功能参数

“约束”。

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'不可分配给'TestWithData'类型。 'SomeConstraint'类型中缺少属性'test'。

我错过了什么?


被修改

正如我说我发现,在终极版分型本(类似)的构建体。当你要定义你减速,你需要提供国家和行动

export type Reducer<S> = <A extends Action>(state: S, action: A) => S; 

现在,我将跳过状态的一部分,所以,我可以写:你可以找到这个定义(终极版“3.7.2”)行动是这样的:

interface MyAction { type: "MY_ACTION" } 

,创造减速很简单:

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) => {...} 

回答

1

对于你给的例子,我不认为通用+约束是我将定义类型的方式(它可能会我会怎么做,在标称的类型系统,而不是在一个结构型系统)。

type SomeType<T> = <A extends SomeConstraint>(item: T, action: A) => void; 

如果你说“的项目必须有一个constraint属性,你可以用得到这个简单的:

type SomeType<T> = (item: T, action: SomeConstraint) => void; 

结构打字负责其余的照顾

在实际的。执行时,可以使用任何与SomeType定义兼容的类型...

const actualImplementation: SomeType<string> = (item: string, action: Test): void => { 

} 

下面是完整版本,记住Test接口要么需要一个constraint属性,要么扩展接口,否则你会缺少使类型兼容的基本属性。

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类型没有错误。

+0

谢谢芬顿,我明白你在说什么,但不幸的是我的例子是错误的,我不小心在两个接口中留下了属性“测试”的名称,但它应该被命名为“约束”。至于为什么这样定义,这是超出我的范围,这实际上是为redux输入类型:导出类型Reducer = (state:S,action:A)=> S; – negyxo

+0

但是除了redux之外,这个构造不应该与以下内容相同: type _SomeType =(item:T,action:A)=> void_? – negyxo