【问题标题】:TypeScript: 'unknown[]' is assignable to the constraint of type 'R', but 'R' could be instantiated with a different subtype of constraint 'unknown[]TypeScript:'unknown[]' 可分配给类型'R'的约束,但'R'可以用约束'unknown[]的不同子类型实例化
【发布时间】:2021-10-14 18:04:14
【问题描述】:

我正在尝试编写一个简单的执行器,它一个接一个地运行 thunk 并将 thunk 的结果返回到一个数组中:

type Thunk<R> = () => R;

type MapToThunk<T extends [...unknown[]]> = T extends  [infer Head, ...infer Tail] ? [Thunk<Head>, ...MapToThunk<Tail>] : [];

function executeSequentially<R extends [...unknown[]]>(thunks: MapToThunk<[...R]>): R {
  let result = [];
  for (const thunk of thunks) {
    result.push(thunk());
  }
  return result;
}

但是 tsc 给了我“类型 'unknown[]' 不能分配给类型 'R'。 'unknown[]' 可分配给类型 'R' 的约束,但可以使用约束 'unknown[]' 的不同子类型来实例化 'R'。”

为什么类型检查会失败?

【问题讨论】:

    标签: typescript typescript-generics


    【解决方案1】:

    我认为您应该以不同的方式键入您的函数。 据我了解,您应该返回一个函数结果数组(返回类型)

    因此,最好推断thunks 中的每个元素并计算其返回类型。

    考虑这个例子:

    type Fn = () => any
    const execute = <Thunk extends Fn, Thunks extends Thunk[]>(thunks: [...Thunks]) =>
      thunks.map<ReturnType<[...Thunks][number]>>((thunk) => thunk())
    
    const result = execute([() => 42, () => 'string']) // (string | number)[]
    
    

    如果你想推断一个元组而不是数组,你可以使用这个例子:

    type Mapped<
      Arr extends Array<unknown>,
      Result extends Array<unknown> = []
      > = Arr extends []
      ? []
      : Arr extends [infer H]
      ? [...Result, MapPredicate<H>]
      : Arr extends [infer Head, ...infer Tail]
      ? Mapped<[...Tail], [...Result, MapPredicate<Head>]>
      : Readonly<Result>;
    
    type MapPredicate<T> = T extends Fn ? ReturnType<T> : never
    
    type Fn = () => any
    const execute = <Thunk extends Fn, Thunks extends Thunk[]>(thunks: [...Thunks]) =>
      thunks.map<ReturnType<[...Thunks][number]>>((thunk) => thunk()) as Mapped<[...Thunks]>
    
    const result = execute([() => 42, () => 'string']) // [number, string]
    

    您可能已经注意到,两个函数的返回类型不同。

    【讨论】:

    • 如果我将type Fn = () =&gt; any 更改为type Fn = () =&gt; unknown,您的代码将停止编译,这让我有点困惑。
    • type Fn = () =&gt; any 用于推断任何不带参数的函数。在这种情况下,any 不应该打扰您。您可能已经注意到,所有推断类型都没有anyunknown 更严格,它不能分配给ReturnType&lt;[...Thunks][number]&gt;。一般来说,函数约束可以使用更常见的类型(...args:any[])=&gt;any
    猜你喜欢
    • 2021-02-13
    • 2021-12-10
    • 2019-12-13
    • 1970-01-01
    • 2023-01-11
    • 2020-11-25
    • 2021-05-22
    • 2022-01-20
    • 2021-06-19
    相关资源
    最近更新 更多