-
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 types and map #6574
Comments
@elbarzil I assume you are only proposing this for heterogeneous tuples. Is that correct? |
@aluanhaddad, I'm just talking about having
(Or maybe I misunderstand what you mean by "heterogeneous tuples"...) |
Map often mutates the types (and is usually the primary purpose of a map)... heterogeneous tuples would be tuples of all the same type (e.g. Based on your example, how would you propose handling something like this? let x: [ string, number ];
let y = [ '1', 2 ].map(x => Number(x)); // what is the type of y? |
@kitsonk, several things I'm confused with: (a) the common meaning of "heterogeneous" in the context of types is different types, especially in lists/arrays/etc where they're contrasted with homogeneous containers where all items have the same type. (b) I'm also confused by "mutates the types" -- types are never mutated, so I don't know what that sentence means... (c) And in your code snip I don't know what the purpose of the first line... But overall, there shouldn't be any particular problem here: you know how to apply a function on elements of an array one by one and deal with the types, and the same logic should apply for using
where each of the
And finally, another variation:
which is supposed to show that I can do this manually, and it almost works except that in the first |
@kitsonk Indeed, that was precisely what I was getting at. @elbarzil If the tuple elements are of the same type, the result of mapping a function over the tuple would always produce a tuple with homogeneous elements. I don't know that changing the result of (x as [T, T]).map(f) from Now, in the case of heterogeneous tuples, there are a few interesting use cases I can think of. class A {}
class B {}
let myAB = [new A(), new B()]; // [A, B]
let myFrozenAB = myAB.map(Object.freeze); // [A, B] That is interesting, but still not that useful, as their are perfectly clean alternative ways to express it. Another use case would be if the function mapped over the tuple has several type specific overloads declared. |
@aluanhaddad, sure it does add value! (Otherwise I wouldn't start this in the first place.) Consider a library that deals with 2d points represented as That's a classic use of a typechecker like TS, and it already has a way to represent this information, it just doesn't get maintained in some places. |
I think there can be an improvement in the type inference system: let x = [0, 1]; // Inferred to be number[]
let y: number[] = x; // OK
let z: [number, number] = x; // Fails |
@FranklinWhale, that's related -- though I know that it's sometimes tricky for these languages to find the "most expected" type. But in my case I was willing to add the type annotations, but (I agree that it seems better to have it infer a |
@elibarzilay: I have just made a related reply in #7799 :) |
See also #3369 |
@FranklinWhale, ah yes, #3369 has the problem I mentioned... (And FWIW, dealing with assignment in a type system with subtypes can make things very complicated in a way that is not obvious. I have a whole section of class notes about the problems it leads to, and it's not really trivial, or expected. The bottom line is that a type of T for a writable variable makes it neither a subtype nor a supertype of any other writable type except for T itself.) |
I'm not convinced that using a tuple is a good way to represent a 2d point or generally a vectorn for some n. Applications of these types will likely want to have specific functionality such as addition, subtraction, magnitude, scaling, dot product, cross product (where defined for n), etc.. |
Here's another case for tuple types: let values = [{id: 1, name: 'anna'}, {id: 2, name: 'bob'}];
let map: Map<number, Object> = new Map(values.map(x => [x.id, x])); This does not currently work. |
@dbrgn your case is actually one of the easiest to work around (in newer TS versions) in a sound manner; despite being a bit verbose: const values = [{id: 1, name: 'anna'}, {id: 2, name: 'bob'}]
const map = new Map(values.map(x => [x.id, x] as [typeof x.id, typeof x]))
// map is Map<number, { id: number; name: string; }> TS has a tuple type; it just prefers to never infer anything as a tuple. |
I have a piece of code with many
foo[]
s that should really be[foo,foo]
-- it would be nicer ifmap
had a type that preserves tuples, so something like this:would work, even if it's some hack with a union of tuples up to some number of elements (I think that I saw something like that around rest arguments, and I imagine that this in a close neighborhood).
I thought that this would be common, but didn't find anything about it. Feel free to dismiss if it is.
The text was updated successfully, but these errors were encountered: