【问题标题】:TypeScript: Type 'T' does not satisfy the constraint '(...args: any) => any'TypeScript:类型 'T' 不满足约束 '(...args: any) => any'
【发布时间】:2020-07-07 19:31:16
【问题描述】:

我有以下 redux-thunk 动作创建者:

function updateInitiator(form_request_id, { to_recipient }) {
  return (dispatch) => {
    const url = `/some/url`;
    const data = { to_recipient };

    return fetch(url, { method: 'PUT', body: JSON.stringify(data) }).then(() => {
      dispatch(fetchResponses());
    });
  };
}

然后我声明函数的类型:

type UpdateInitiator = typeof updateInitiator;

我正在尝试导出绑定 thunk 操作的类型。简而言之,当action creator在react-redux中被“绑定”时,它会自动调用dispatch返回的函数,然后返回that内部函数的返回结果。我正在尝试为这种行为声明一个类型。如果我在没有泛型的情况下这样做,它会起作用:

type BoundUpdateInitiator = (...args: Parameters<UpdateInitiator>) => ReturnType<ReturnType<UpdateInitiator>>;

但是当我尝试为任何绑定函数声明一个泛型类型时,我遇到了一些麻烦:

type BoundThunk<T> = (...args: Parameters<T>) => ReturnType<ReturnType<T>>;
type BoundUpdateInitiator = BoundThunk<UpdateInitiator>;

这给了我错误:

error TS2344: Type 'T' does not satisfy the constraint '(...args: any) => any'.

236 type BoundThunk<T> = (...args: Parameters<T>) => ReturnType<ReturnType<T>>;
                                              ~

error TS2344: Type 'ReturnType<T>' does not satisfy the constraint '(...args: any) => any'.
  Type 'unknown' is not assignable to type '(...args: any) => any'.
    Type '{}' provides no match for the signature '(...args: any): any'.

236 type BoundThunk<T> = (...args: Parameters<T>) => ReturnType<ReturnType<T>>;
                                                                ~~~~~~~~~~~~~

error TS2344: Type 'T' does not satisfy the constraint '(...args: any) => any'.

236 type BoundThunk<T> = (...args: Parameters<T>) => ReturnType<ReturnType<T>>;
                                                                           ~

我可以隐约理解T 可能不是函数,同样ReturnType&lt;T&gt; 也可能不是函数,而这种泛型类型可能不考虑这些情况。但是,我无法理解如何 解释它们。理想情况下不允许他们。有什么建议吗?

【问题讨论】:

  • 这就是泛型类型约束的用途。查看ReturnType&lt;T&gt; 和Parameters&lt;T&gt; 的定义,您会立即看到要写什么。例如:type BoundThunk&lt;T extends (...args: any[]) =&gt; any&gt; = (...args: Parameters&lt;T&gt;) =&gt; stuff
  • @AluanHaddad 成功了。如果你想回答我会标记为正确的。

标签: reactjs typescript redux-thunk


【解决方案1】:

为了实现这一点,我们将使用泛型类型约束。

这实际上是指定语言提供的实用程序类型Parameters&lt;T&gt; 和ReturnType&lt;T &gt; 的类型参数以及导致错误的原因。

为了使用我们的类型参数实例化一个泛型类型,比如ReturnType&lt;T&gt;,我们的类型参数必须至少与ReturnType&lt;T&gt; 中的类型参数T 一样受到限制。

通过查看ReturnType&lt;T&gt;的定义我们可以确定最小约束(正式称为上限),我们需要应用和相关的语法

type ReturnType<T extends (...args: any) => any> =
    // details

不要担心实施(在= 之后),因为这是一个更广泛的主题。在这种情况下,我们将重点关注在T 的声明中使用extends 关键字指定的T 的约束。

因此,为了通过BoundThunk&lt;T&gt; 将T declared 传递给ReturnType&lt;T&gt;,我们必须对其进行约束以满足上述要求(注意Parameters&lt;T&gt; 具有相同的约束)。

type BoundThunk<T extends (...args: any) => any> =
    (...args: Parameters<T>) => ReturnType<ReturnType<T>>;

然而,我们对T 的要求实际上更多限制,因为我们应用了两次ReturnType&lt;T&gt;,ReturnType&lt;ReturnType&lt;T&gt;&gt;,这意味着T 是一个高阶函数,在这种情况下是一个函数返回一个函数。

因此,我们将相应地改进我们的约束

type BoundThunk<T extends (...args: any) => (...args: any) => any> =
    (...args: Parameters<T>) => ReturnType<ReturnType<T>>;

【讨论】:

  • 感谢您的彻底回复!有什么方法可以在不使用any 的情况下声明类型?它看起来不像,但我很好奇。一般来说,我知道使用比any 更具体的类型是理想的,尽管在这种情况下它看起来不会传播到任何地方。
  • 是的,您绝对可以使用更具体的类型,例如T extends (s: string, b: boolean) =&gt; number,如果我们有更多信息,这是个好主意。然而值得注意的是,上面的anys 实际上并没有产生一个接受任何参数并返回any 类型结果的函数,它们只是允许将 BoundThunk 类型应用于返回另一个函数的任何函数.基本上any 在约束中使用时不会删除类型信息,它使约束不那么具体。约束就像超类型
  • 该死的,@AluanHaddad,这些都是脑筋急转弯
猜你喜欢
  • 2020-02-24
  • 2020-10-25
  • 1970-01-01
  • 1970-01-01
  • 2019-12-18
  • 2013-09-02
  • 1970-01-01
  • 2019-02-10
  • 2021-05-26
相关资源
最近更新 更多