-
Notifications
You must be signed in to change notification settings - Fork 12.6k
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
tuple type don't check number of elements #5259
Comments
Tuples are basically objects with numeric properties. So The second doesn't compile for a different reason, which is just that the array The first reason basically makes sense to me, although it would be nice if Typescript had better checking here. The second reason is a side effect of using arrays to represent tuples, and is a bit unfortunate. For example, this doesn't compile either: var bar: (number | string)[] = [1, 2, ''];
var foo: [number, number, string] = bar; // (number | string)[] is not assignable to [number, number, string]
var baz: [number, number, string] = [1, 2, '']; // OK! |
Second doesn't compile because 1 isn't a string. You gave it a type of [string,string]. |
According to the spec section 3.3.3, the type [number, string] is equivalent to an interface that extends Array:
The unfortunate side effect of this is that extra elements in a tuple assignment are ignored, but only if they are of a type that is already present in the tuple. That's because I think this is a bug in the spec, but I'm not at all sure how to fix it. Maybe an ad-hoc rule that says the lengths have to match, or maybe there's an existing way to fix it in the language. |
Tuples are already quite unsafe because you can do the following: var tuple: [number, string] = [0, ""];
for (var i in tuple) {
tuple[i] = ""; // Succeeds because string is assignable to number | string
}
tuple[0]; // type is number, but should be string I think the goal of giving the user the right type needs to be relaxed for tuples, relative to other parts of the language. On the one hand, there are no restrictions on what users can do with tuples, but on the other hand, users may make strong assumptions about what the tuple will contain at each index (that's what makes it a tuple). This disconnect between expectation and reality should probably be addressed more broadly if any changes to the type checking rules for tuples are considered. |
This isn't a bug, it is working as designed. Our view is that tuple is an array for which we have static knowledge of the individual types of the first N elements and for which the element type is the union of the types of those N elements. We allow more than N elements to be present (since there's really not much we can do to prohibit it), but we do require those elements to have a compatible type. |
Must say I feel a bit sad about this. I felt a bit excited when I read about tuples in the typescript handbook:
But I was expecting something to use like C# tuples: (dotnet/roslyn#347) |
Tuples should have a fixed size or number of elements. That's a property: |
Identical is not the same as subtype. |
So there is no way any way to fixate number of elements of the tuple or list in typing? To me this is a big disadvantage. |
type fixed = [number, number] & { 2: void };
// Error
var x: fixed = [3, 3, 3]; |
but it doesn't work with 2 either: type fixed = [number, number] & { 2: void };
// Error
var x: fixed = [3, 3];
|
Sorry type fixed = [number, number] & { 2?: void };
// Error
var x: fixed = [3, 3, 3];
// OK
var y: fixed = [3, 3]; |
@RyanCavanaugh cool, thank you! Btw when was this feature added? |
That's worked for as long as intersection types (or tuples? whichever came first) have existed |
This is the boldest "it's not a bug, it's a feature" case I've seen in years. Respect.
Maybe it's not simple to prohibit the number of items a tuple contains, but what about reading the tuple? Could be prohibited using an index larger than the tuple size? const t: [number, number] = [1, 2, 3]; // Works, apparently not possible to prohibit consistently
t[1]; // works
t[2]; // Error, [number, number] only has 2 elements Regarding prohibiting the number of elements a tuple has, I imagine you say it's not possible because of the mutable nature of the arrays in javascript. However, the majority of languages that contain the tuple data structure define them as immutable, even in those languages prone to mutability, like Python. Have you considered making tuples immutable? That could be done easily, and would allow typescript to stop saying that a tuple has unlimited size by design... |
@arnauorriols see #17765 |
The following compiles,
while this one not:
The first one should not compiles, since the initializer has 3 elements while the type says 2.
The text was updated successfully, but these errors were encountered: