Here is the code snippet to consider:
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"]
In essence, I am trying to unwrap a tuple following a specific structure (tuple of Wrap<Values>
). However, there seems to be a type check error with the pick()
function in WrapTuple
. Here are some questions regarding this issue:
- Could the reason for this error be because
Unwrap<Tuple>
might not have a consistent shape due to conditional type inference? - Is there a way to resolve this without resorting to casting it as
as unknown as Value
?
Update: Linda pointed out that mapping a tuple does not yield another tuple. To address this, I attempted to implement my own version of map mentioned in this here:
interface Array<T> {
map<U>(callbackfn: (value: T, index: number, array: T[]) => U,
thisArg?: any): { [K in keyof this]: U }
}
However, even with this implementation, I still need to assert the map
method's return value as Value
:
pick(): Value { return this.ts.map(a => a.pick()) as Value }