Repository navigation
Tuple types accepting incorrect data #19463
Description
Activity
The type of
string[]and[string, string]is assignable to[string]. Tuple types are not checked for excess elements when fresh, unlike objects, so the right hand side is assignable to left hand side.It is arguable though when the array is fresh, it should follow the same rules as #3823 for objects.
DanielRosenwasser commented
on Oct 25, 2017 MemberMore actionsThink of it like this
interface Tuple1<T> extends Array<T> { 0: T; } interface Tuple2<T, U> extends Array<T | U> { 0: T; 1: U; } declare let a: Tuple1<string>; declare let b: Tuple2<string, string>; a = b; // works, 'b' is also viewed as a `string[]` with a `0: string`
DanielRosenwasser commented
on Oct 25, 2017 MemberMore actionsSee also: #6229
Reacted by Kitson Kelly, Aluan Haddad and Igor Oleinikov- addedDuplicateAn existing issue was already createdAn existing issue was already created
on Oct 25, 2017 Did you make some specific decision to untype arrays then, compared to normal types? I don't see why this is any different from:
let a: { x: number } = { x: 4, y: 5 };... which compile errors as you'd expect. If this is intended typescript behavior permanently, then we will have to excise all usage of tuples from our codebase and go to slower object-based types everywhere. This implementation is almost completely un-typesafe. :(
DanielRosenwasser commented
on Oct 25, 2017 MemberMore actionslet a: { x: number } = { x: 4, y: 5 };
TypeScript's original behavior allowed this. The motivating example for disallowing it was options-bag-style APIs where people were misspelling optional properties. Are you frequently running into excess tuple errors? (edit: not being cheeky, I'm legitimately looking for motivating use cases)
Yes, we just made a correction to our codebase to change over a hundred usages of tuples that were being used incorrectly.
The question in my book is what the pros and cons of each way are. What are the pros of allowing you to do what feels like, to me, "invalid" assignments to tuples? I.e. why SHOULD it be allowed to do:
let a: [string] = [ 'hi', 12345 ];That feels like it's an engineer bug in 100% of circumstances, and if we have the ability to fix it with TSC, then we should.
Actually that example is disallowed. Excess assignment slots only work when the excess values are assignable to one of the member of the tuple. 🤷♂️
let a: [ string, number ] = [ 'hi', 12345, 'foo' ]; // ok let b: [string] = ['hi', 12345]; // bad let c: [string | number] = ['hi', 12345]; // ok
Personal opinion too, when the array is fresh, it should be strictly checked against the left hand, because as David de Regt (@deregtd) indicates, how is that ever a desired situation? Especially considering how the following works:
let a: [string, number] = ['hi', 12345]; let b: [string] = a; // not assignable let c: [string|number] = a; // ok
That, again, while maybe sound from a type system perspective, I can't see why the assignment to
bis bad whilecis good from an identifying constructs that are likely to be errors. Either both are desirable, or neither.Reacted by David de Regt, Sean M. Vieira and Giulio Canti- addedSuggestionAn idea for TypeScriptAn idea for TypeScriptIn DiscussionNot yet reached consensusNot yet reached consensusand removedDuplicateAn existing issue was already createdAn existing issue was already created
on Oct 26, 2017 From #19536, we would like to consider one of two alternatives here:
- Treat all tuples as exact types, where the
lengthproperty is manifest in the type, and two tuples are only assignable if they have the exact same length. Tuples will need to beReadonlyArrayfor this to work. We will have to include this under a strict flag. - Apply freshness rules on tuple literals, and flag excess members just like we do with objects.
Reacted by Kitson Kelly, Aluan Haddad and Asad Saeeduddin- Treat all tuples as exact types, where the
#1 sounds perfect to me. The way we often use tuples, it's basically just a quick and strong dynamic type that doesn't require wrapping in an interface.
- addedAwaiting More FeedbackThis means we'd like to hear from more people who would be helped by this featureThis means we'd like to hear from more people who would be helped by this featureand removedIn DiscussionNot yet reached consensusNot yet reached consensus
on Oct 30, 2017 RyanCavanaugh commented
on Oct 30, 2017 MemberMore actionsSee notes in #19585
Mohamed Hegazy (@mhegazy) (1) seems more preferable and is what #6229 and #17765 propose.
Nathan Shively-Sanders (@sandersn) I guess you meant
6629#6229.My vote goes for freshness, unless the full Strict/Open length tuples proposal gets implemented. Working with non-aliasable tuples is just painful. It will lead to many overloads, which is hardly ideal.
E.g. this is a Haskell library trying to provide uniform usage patterns for tuples of disparate arities: https://github.com/augustss/tuple. The implementation code consists of ugly, automatically generated type class instances (e.g. Select). I don't think we'd like to go in that direction.
Should be fixed by #17765
- addedFixedA PR has been merged for this issueA PR has been merged for this issueand removedAwaiting More FeedbackThis means we'd like to hear from more people who would be helped by this featureThis means we'd like to hear from more people who would be helped by this feature
on Nov 8, 2017 - locked and limited conversation to collaborators
on Jun 14, 2018
TypeScript Version: 2.6.0-rc
Code
Expected behavior:
Error: [string, string] is not compatible with [string].
Actual behavior:
Compiles A-ok