处理未包装的可变元组类型

Hug*_*ira 7 type-inference tuples typescript variadic-tuple-types

考虑以下代码:

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"]
Run Code Online (Sandbox Code Playgroud)

基本上我正在解开一个我知道遵循某种形状(的元组Wrap<Values>)的元组。该pick()函数WrapTuple应该保证展开的类型(提供相同形状的回归Unwrap<Tuple>),虽然我在该行获得了类型检查错误。问题:

  1. 这是因为Unwrap<Tuple>条件类型推断不能保证具有相同的形状吗?
  2. 是否可以在不强制演员的情况下使其工作as unknown as Value

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

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

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

pick(): Value { return this.ts.map(a => a.pick()) as Value }
Run Code Online (Sandbox Code Playgroud)

cap*_*ian 0

更新

这是解决方法:

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]
Run Code Online (Sandbox Code Playgroud)

操场

看起来它通过方法重载按预期工作

在这里您可以找到更多元组的解决方法。这是我的博客