【问题标题】:Dealing with Unwrapped Variadic Tuple Types处理展开的可变元组类型
【发布时间】:2021-06-05 17:04:45
【问题描述】:

考虑以下代码:

interface Wrap<Value> {
  pick(): Value
}

class WrapConstant<Value> implements Wrap<Value> {
  constructor(public readonly a: Value) { }
  pick(): Value { return this.a }
}

type Unwrap<Wrapped> = { [P in keyof Wrapped]: Wrapped[P] extends Wrap<infer Value> ? Value : never }

class WrapTuple<Tuple extends Wrap<unknown>[], Value = Unwrap<Tuple>> implements Wrap<Value> {
  readonly ts: Tuple
  constructor(...t: Tuple) { this.ts = t }

  pick(): Value { return this.ts.map(a => a.pick()) }                // fails to type check
}

type T1 = Unwrap<[WrapConstant<number>, WrapConstant<string>]>       // [number, string]

new WrapTuple(new WrapConstant(1), new WrapConstant("hello")).pick() // [1, "hello"]

基本上我正在解开一个我知道遵循某种形状的元组(Wrap&lt;Values&gt; 的元组)。 WrapTuple 中的 pick() 函数应该保证返回相同形状的未包装类型(由 Unwrap&lt;Tuple&gt; 提供),尽管我在该行中遇到类型检查错误。问题:

  1. 这是因为 Unwrap&lt;Tuple&gt; 不能保证由于条件类型推断而具有相同的形状吗?
  2. 是否可以在不强制转换as unknown as Value 的情况下使其工作?

更新:正如 Linda 所说,映射元组不会产生元组。我尝试按照here的建议合并我自己的地图声明:

interface Array<T> {
  map<U>(callbackfn: (value: T, index: number, array: T[]) => U, 
         thisArg?: any): { [K in keyof this]: U }
}

但这仍然需要将map 断言为Value

pick(): Value { return this.ts.map(a => a.pick()) as Value }

【问题讨论】:

  • .map 总是会失败类型检查,因为它返回一个可变长度的数组而不是一个元组。
  • 没错,map 永远不会返回元组,因为它在可变数组上运行

标签: typescript tuples type-inference variadic-tuple-types


【解决方案1】:

更新

这里是解决方法:

interface Wrap<Value> {
    pick(): Value
}

class WrapConstant<Value> implements Wrap<Value> {
    constructor(public readonly a: Value) { }
    pick(): Value { return this.a }
}

type Unwrap<Wrapped> = { [P in keyof Wrapped]: Wrapped[P] extends Wrap<infer Value> ? Value : never }

class WrapTuple<Tuple extends ReadonlyArray<Wrap<unknown>>> implements Wrap<unknown> {
    readonly ts: Tuple
    constructor(...ts: [...Tuple]) {
        this.ts = ts
    }

    pick(): Unwrap<[...Tuple]> // <-- added overload
    pick() {
        return this.ts.map(a => a.pick())
    }
}


const foo = new WrapTuple(new WrapConstant(1), new WrapConstant("hello")).pick() // [number, string]

Playground

看起来它在方法重载的情况下按预期工作

Here 你可以找到更多使用元组的解决方法。这是我的博客

【讨论】:

  • 感谢您的解决方法,但我的问题是正是,因为我想处理元组。
  • @HugoSerenoFerreira 你可以使用as 运算符吗?
  • @HugoSerenoFerreira 我更新了。希望它仍然相关
猜你喜欢
  • 2013-12-01
  • 1970-01-01
  • 2022-12-03
  • 1970-01-01
  • 1970-01-01
  • 2017-11-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多