question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

`Tuple & nominal` not recognised as tuple in spread parameter

See original GitHub issue

Bug Report

🔎 Search Terms

Nominal, Spread, Tuple,

🕗 Version & Regression Information

  • This is the behavior in every version I tried, and I reviewed the FAQ for entries about spread and intersections

⏯ Playground Link

Playground link with relevant code

💻 Code

declare let a: [number, number, number] & { _nominal_a: never }
function b(...params: [number, number, number]) {}
b(...a) // Error: A spread argument must either have a tuple type or be passed to a rest parameter.

🙁 Actual behavior

The error in the code example is thrown, because TypeScript does not detect it as being a tuple. In roblox-ts, we use a nominal marker type to indicate a special kind of tuple. This bug means that this tuple type can then not be spreaded into a fixed argument function. Our issue: https://github.com/roblox-ts/roblox-ts/issues/1537

🙂 Expected behavior

This is a tuple type, and should therefore be recognised as such.

Issue Analytics

  • State:open
  • Created 2 years ago
  • Reactions:7
  • Comments:6

github_iconTop GitHub Comments

1reaction
Dionysusnucommented, Jan 13, 2022

What I find somewhat trubling, beyond TypeScript loosing the plot in the first place, is that Array<T> will produce the same error, eg.

This usually makes sense, because you don’t know the Array’s length, which is why it’s (as the correct behaviour) not considered a tuple. That’s part 1, and then part 2, I believe this not working in this case is a separate missing behaviour, which is that normal parameters need to be filled manually, not being considered to be part of the rest parameter. What I mean by that is that a function like a(obj: object, ...other: object[]) will not allow a call like a(...objects) where objects is Array<object>, despite this being type-compatible.

0reactions
scottwillmoorecommented, Apr 23, 2022

I am not sure if this is related, or supposed to occur… However, when attempting to brand or flavor a tuple it appears that TypeScript is no longer able to restrict property access past the length of the tuple.

Example

declare const id: unique symbol;
type Id<T> = { readonly [id]: T };

type Brand<T, U> = T & Id<U>;
type PartialBrand<T, U> = T & Partial<Id<U>>; // Also known as Flavor.

declare const pointId: unique symbol;
type Point = PartialBrand<[number, number], typeof pointId>;

const point = (x: number = 0, y: number = 0): Point => [x, y];

const add = (a: Point, b: Point, c: Point = point()): Point => {
  c[0] = a[0] + b[0];
  c[1] = a[1] + b[1];
  return c;
};

const a = point(0, 1);
const b = point(2, 3);
const c = add(a, b);

console.log(c);

c[0] = 4;
c[1] = 5;
c[2] = 6; // Should be an error!

console.log(c);

Playground Link

It appears that the expansion of the type includes [x: number]: number. Maybe I should open this a separate issue?

type DeepExpand<T> = T extends object ? T extends infer O ? { [K in keyof O]: DeepExpand<O[K]> } : never : T;
type ExpandPoint = DeepExpand<Point>;

// type ExpandPoint = {
//   [x: number]: number;
//   ...
// }
Read more comments on GitHub >

github_iconTop Results From Across the Web

A spread argument must either have a tuple type or be passed ...
I have errors: A spread argument must either have a tuple type or be passed to a rest parameter. Can someone can help...
Read more >
Documentation - TypeScript 3.0
Tuples in rest parameters and spread expressions. TypeScript 3.0 adds support to multiple new capabilities to interact with function parameter lists as tuple...
Read more >
Returning Multiple Values Using Tuples in C# - dummies
In versions of C# prior to C# 7.0, every return value was a single object. It could be a really complex object, but...
Read more >
Java 14 Feature Spotlight: Records - InfoQ
A record can be best thought of as a nominal tuple; it is a transparent ... Specifically, they are not intended as a...
Read more >
Google TypeScript Style Guide
Do not use the opt_ prefix for optional parameters. ... This can be used to name primitives, unions, tuples, and any other types....
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found