函数参数的 typescript 通用约束

标签 typescript

编辑:
将接口(interface)中的“测试”固定为“约束”

我无法理解通用约束在 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 ) => {}

效果很好,但是,当我想扩展测试接口(interface)时(我们称之为TestWithData):
interface TestWithData  { constraint: string, payload: any }
const some : SomeType<string> = (s: string, c: TestWithData ) => {}

我得到一个编译时错误:

错误 TS2322:类型“(s:字符串,c:TestWithData)=> void”不可分配给类型“SomeType”。
参数“c”和“action”的类型不兼容。
类型“A”不可分配给类型“TestWithData”。
类型“SomeConstraint”不可分配给类型“TestWithData”。
“SomeConstraint”类型中缺少属性“test”。

我错过了什么?

已编辑

正如我所说,我在 redux 类型中发现了这个(类似的)构造。你可以找到这个定义(redux“3.7.2”):
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) => {...}

最佳答案

对于您给出的示例,我不认为泛型 + 约束是我定义类型的方式(这可能是我在名义类型系统中的方式,但不是在结构类型系统中)。

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

如果您说“该项目必须具有 constraint 属性,您可以使用更简单的方法来获得它:
type SomeType<T> = (item: T, action: SomeConstraint) => void;

结构类型负责其余的工作。

这是我的更新版本,因为之前的答案在 TypeScript 3.8.3 中停止工作。我已将约束设为通用,因为约束将与项目的类型相同。因为可以推断参数类型,所以我们不需要显式声明它们(即,我们不需要写 string 三次...像这样 const actualImplementation: SomeType<string> = (item: string, action: string): void => { } - 我们可以只写一次作为类型参数.
interface SomeConstraint<T> {
    constraint: T
}

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

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

const a: SomeConstraint<string> = { constraint: '' };

actualImplementation('', a);

上面例子的关键是实际的实现可以是你的Test键入没有错误。

关于函数参数的 typescript 通用约束,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46559663/

相关文章:

typescript - 如何从 Vue Composition API/Vue 3.0 + TypeScript 中的组合函数访问根上下文?

reactjs - 将 WebWoker 与 create-react-app 和 typescript 一起使用

angular - 警报 Controller 输入框验证

javascript - 使用 InjectionToken 进行注入(inject)?

mysql - LoopBack 4 REST API 使用 Mysql 获取记录的示例

javascript - 使用 XMLHttpRequest 解析 JSON 时返回空值

javascript - Fluid-Framework 和 Signalr 之间的区别

Angular 2 : How to display console response data?

javascript - 使用带有 typescript 的样式化组件 "as" Prop

javascript - 如何从一组日期中获取最新日期? - JavaScript/ typescript