6

I have this

Type T = Params<[Tuple1, Tuple2]> // eg [[string], [number]]

How to make of it (flatten)

Type Flatten<T> = Params<[string, number]> 

2 Answers 2

4

We can do that by mapped types. Consider the code:

type T = Params<[Tuple1, Tuple2]>

// utility type
type Flatten<T extends any[]> = {
  [K in keyof T]: T[K] extends any[] ? T[K][0] : T[K]
}
type Result = Flatten<T>
// evaluates into [string, number]

const a: Result = ['a', 1] // correct value of the type

Pay attention how Flatten works:

  • [K in keyof T] - means we want to have all keys, so in tuple say elements
  • T[K] extends any[] ? T[K][0] : T[K] - we say if the value of the element on the given key is an array then give me a type of an first element of this array (index 0), if not leave it as is, as there is nothing to be flatten

If your tuples consider more then one type of the element, then above solution will take the first only. So for tuple [string, number] it will produce the string. If we want to gather all possible types inside the tuple we can create more sophisticated type. Consider:

type Flatten<T extends any[]> = {
  [K in keyof T]: T[K] extends any[] ? T[K][Exclude<keyof T[K], keyof any[]>] : T[K]
}
  • T[K] extends any[] ? T[K][Exclude<keyof T[K], keyof any[]>] : T[K] means that if our element is an array then get me types of all elements, but remove types of values in array prototype.

In the result Flatten<Params<[string, number]>> will produce [string | number]. So it depends what is your goal.


The last proposition is, if you don't consider other types and only nested array/tuples, we can avoid conditional types. Consider last solution:

type Flatten<T extends E[], E extends any[] = any[]> = {
  [K in keyof T]: T[K][Exclude<keyof T[K], keyof any[]>]
}

Above type is more restrict as it works with only [[]] but is more concise and specific.

Sign up to request clarification or add additional context in comments.

10 Comments

works great thanks, only problem if it are function params that it loses the param name like x: string now it becomes param_0: string. best would be something like [...TupleParams1, ...TupleParams2] but that doesnt work
@luky can you be more clear hear, not fully follow. What you need to pass to the function extacly?
U can use the result type like - function f(...args: Flatten<T>) {}
hm it is actually two Params of two functions but i will try it again because TS helper Parameters<> also capture the param names eg "x: string" etc
Not so simple to solve. I get you but I think we are far away from the original question. My suggestion is to create another one. Take a look that orginal question does not say anything about function arguments at all.
|
3

You can now define recursive types:

type Flatten<T> = (
    T extends [] ? [] :
    T extends [infer T0] ? [...Flatten<T0>] :
    T extends [infer T0, ...infer Ts] ? [...Flatten<T0>, ...Flatten<Ts>] : [T]
)
type T = Flatten<[[number, number, []], string, [[]], [string, [number, string]]]>
// T is [number, number, string, string, number, string]

Playground.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.