0

I have a function which takes a tuple and returns a tuple where the elements are related one-to-one through generic types. I fail to write an implementation that uses that tuple. Here is a contrived example:

export type WrapA<T extends readonly unknown[]> = {
    [K in keyof T]: {x: T[K]};
}

export type WrapB<T extends readonly unknown[]> = {
    [K in keyof T]: {y: T[K]};
}

function a<T extends readonly unknown[]>(t: WrapA<T>) : WrapB<T> {
    // Question 2
    if(t.length == 0) {
        return []  // Type 'never[]' is not assignable to type 'WrapB<T>'.ts(2322)
    }
    // Question 1
    return t.map(i => {y: i.x})  // Type 'void[]' is not assignable to type 'WrapB<T>'.ts(2322)
}

// Question 3
// Type parameters are required, for b and c to be 'narrowed'
const [b, c] = a<[number, string]>([{x: 1}, {x: "s"}])

Question 1: How can I relate the parameter type to the return type in the implementation (w/o any obviously)? In this example I'm using map but it could also have side effects, as long as the elements of t map to the elements of the return value.

Question 2: Can I "type narrow" t to any empty list? This is useful if I want to skip expensive computations. I tried checking the length and using a type guard:

function isEmptyTuple<T extends unknown[]>(t: T) : t is [] {
    return t.length == 0
}
// A type predicate's type must be assignable to its parameter's type.
//  Type '[]' is not assignable to type 'T'.
//    '[]' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'unknown[]'.ts(2677)

Question 3: If I omit the type parameters when I call a the return type is less specific (string | number). Is there a better way to define the types such that the implied type argument is specific?

fischerman
  • 500
  • 4
  • 12
  • Please [edit] this to ask a single primary question, or it risks being closed with "Needs more focus: This question currently includes multiple questions in one. It should focus on one problem only." – jcalz Feb 23 '23 at 14:48
  • This feels like a duplicate of [this question](https://stackoverflow.com/q/66091118/2887218) but until this narrows to a single thing it's hard to tell for sure – jcalz Feb 23 '23 at 14:50
  • I think you have to cast here: https://tsplay.dev/mq9qrm – kelsny Feb 23 '23 at 14:51

0 Answers0