[TypeScript] Variadic Tuple Types V4 ...T

https://www.typescript-training.com/course/making-typescript-stick/03-recent-updates-to-typescript/#variadic-tuple-types

Before V4, for type, it is possible to use ...spread[] as the last element of the tuple.

// Worked this way, even before TS 4.x
enum Sandwich {
  Hamburger,
  VeggieBurger,
  GrilledCheese,
  BLT
}
type SandwichOrder = [
  number, // order total
  Sandwich, // sandwich
  ...string[] // toppings
]
 
const order1: SandwichOrder = [12.99, Sandwich.Hamburger, "lettuce"]
const order2: SandwichOrder = [14.99, Sandwich.Hamburger, "avocado", "cheese"]
// Error: Type 'string' is not assignable to type 'Sandwich'.
const order_with_error: SandwichOrder = [
  10.99,
  "lettuce"
]

 

The same as generics for that spread type at the end of the tuple:

// Worked this way, even before TS 4.x
type MyTuple<T> = [number, ...T[]]

const x1: MyTuple<string> = [4, "hello"]
const x2: MyTuple<boolean> = [4, true]

 

It’s important to note that, before TS 4.0 we had to use ...T[]

 

What's the problem then?

enum Sandwich {
  Hamburger,
  VeggieBurger,
  GrilledCheese,
  BLT
}
type SandwichOrder = [
  number, // order total
  Sandwich, // sandwich
  ...string[] // toppings
]
 
const order1: SandwichOrder = [12.99, Sandwich.Hamburger, "lettuce"]
 
/**
 * return an array containing everything except the first element
 */
function tail<T>(arg: readonly [number, ...T[]]) {
  const [_ignored, ...rest] = arg
  return rest
}
 
// const orderWithoutTotal: (string | Sandwich)[]
const orderWithoutTotal = tail(order1)

We expected `orderWithoutTotal` should be [Sandwich, ...string[]]. Instead of (string | Sandwich)[] 

 

From V4, we are able to get correct type:

function tail<T extends any[]>(arg: readonly [number, ...T]) {
    // add _ to _ignored, to stop Typescript unsed variable compalins
    const [_ignored, ...rest] = arg;
    return rest;
}

const order1: SandwichOrder = [12.99, Sandwich.Hamburger, "lettuce"]
// const result: [Sandwich, ...string[]]
const result = tail(order1)

 Try out

 


 

We can also now use more than one ...spread in a single tuple

type MyTuple = [
  ...[number, number],
  ...[string, string, string]
]
// const x: [number, number, string, string, string]
const x: MyTuple = [1,2,'a', 'b', 'c']

 

It’s important to note that only one ...rest[] element is possible in a given tuple, but it doesn’t necessarily have to be the last element

// Good
type t1 = [...[number, number], ...string[]]
type t2 = [boolean, ...number[], string]

// Bad
type b1 = [...number[], ...string[]]

 

posted @ 2022-07-11 16:03  Zhentiw  阅读(36)  评论(0编辑  收藏  举报