Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow rest elements to follow other rest elements in tuple types #55446

Closed
wants to merge 1 commit into from

Conversation

Andarist
Copy link
Contributor

@Andarist Andarist commented Aug 21, 2023

I think that this restriction is somewhat artificial and doesn't bring a lot of value. Those are allowed and work OK:

type Ok1 = [...Array<number>, ...Array<string>]

type Alias = string[]
type Ok2 = [...number[], ...Alias]

@typescript-bot typescript-bot added the For Uncommitted Bug PR for untriaged, rejected, closed or missing bug label Aug 21, 2023
@typescript-bot
Copy link
Collaborator

This PR doesn't have any linked issues. Please open an issue that references this PR. From there we can discuss and prioritise.

@ssalbdivad
Copy link

Thoughts on going the other direction and erroring in both cases?

[...number[], ...string[]] does imply more than just (number | string)[]. Barring a robust sequential representation and some advanced narrowing to make it usable, it feels safer just to error rather than implicitly weaken the constraints.

@Andarist
Copy link
Contributor Author

I dont rly think that multiple variadic elements in a tuple are usable. Even trailing non-variadic elements are already quirky to handle at runtime

@ssalbdivad
Copy link

@Andarist Yeah you convinced me it wouldn't be worth implementing last time we discussed it.

That said, I think given that, do you think disallowing every form of [...Array<number>, ...Array<string>] could be the safer option to avoid implicitly weakening the defined type?

@Andarist
Copy link
Contributor Author

It would be a breaking change. The behavior of combining different tuple types through a normalization algorithm sounds useful to me. It also supports more than just multiple rest elements, optional ones are also supported, and with your proposal, all of that would have to be an error. Example of what works today:

type A = [number, string?];
type B = [...boolean[], boolean];
type C = [bigint, ...bigint[], ...B, ...A]; // [bigint, ...(string | number | bigint | boolean | undefined)[]]

@ssalbdivad
Copy link

@Andarist I'm not suggesting A and B not continue to work as they do currently, just that C not be implicitly weakened to a union of its elements.

Whether TS supports it or not (and I understand why doing so doesn't seem worthwhile), [...number[], ...string[]] has a distinct meaning as a type that is stricter than (number | string)[]. I don't see a good reason to allow definitions like that that can't actually be enforced over requiring the weaker form directly.

@Andarist
Copy link
Contributor Author

That still would be a breaking change for cases like this:

type JoinArrays<T1 extends readonly unknown[], T2 extends readonly unknown[]> = [...T1, ...T2]
type Result1 = JoinArrays<string[], number[]> // (string | number)[]

This behavior is rather useful and we can't disallow JoinArrays being a thing since very useful things would get disallowed:

type JoinArrays<T1 extends readonly unknown[], T2 extends readonly unknown[]> = [...T1, ...T2]
type Result2 = JoinArrays<[number, number], [boolean]> // [number, number, boolean]

We have variadic elements here (and not rest ones). Technically it's trivial~ to allow this while disallowing multiple rests. Syntactically they both look the same though. I find it a hard sell for only one of them to work. If the generic variant with variadic elements works and we can "join" array types using it then IMHO it only makes sense for the non-generic case to work in the same way.

@ssalbdivad
Copy link

@Andarist Good point, I hadn't considered this. That may actually help clarify some of the motivation for the seemingly arbitrary existing behavior.

Perhaps the intention was to disallow multiple rest elements when it would always just be reduced to a union. If that is the case, Array<T>, ReadonlyArray<T> etc. should also error when used like this, whereas aliases (ideally only those bound to generic parameters) would continue to be allowed, falling back to the union behavior when necessary.

While I think this approach could help avoid some unexpected results, neither approach feels great and I understand wanting to standardize the behavior. Given this, I think the ideal solution really would be to implement a restrictive version of [...number[], ...string[]] as a builtin type, but from an ROI perspective it's probably just not worthwhile.

@sandersn sandersn added this to Not started in PR Backlog Sep 6, 2023
@sandersn sandersn moved this from Not started to Waiting on reviewers in PR Backlog Sep 7, 2023
@Andarist
Copy link
Contributor Author

Andarist commented Jan 12, 2024

superseded by 70715ea (that belongs to #57031 )

@Andarist Andarist closed this Jan 12, 2024
PR Backlog automation moved this from Waiting on reviewers to Done Jan 12, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
For Uncommitted Bug PR for untriaged, rejected, closed or missing bug
Projects
PR Backlog
  
Done
Development

Successfully merging this pull request may close these issues.

None yet

4 participants