type-fest
type-fest copied to clipboard
Add `UnionToUnorderedTuple` type
Thanks for contributing.
It would be great if you could check out the previous attempt at adding this type and address the feedback given there (if relevant): https://github.com/sindresorhus/type-fest/pull/167
hi @sindresorhus , thanks for pointing this out. Yes indeed this implementation has exactly the same issues as during previous attempt. The problem is in TypeScript itself. It doesn't guarantee that tuple will always preserve order of it's elements. Closing this for now
hi @sindresorhus, just found this https://github.com/microsoft/TypeScript/issues/44116#issuecomment-849833071
Unions are unordered and any code that attempts to observe a union's order is asking for undefined behavior.
So, maybe we shouldn't expect tuple to be ordered in the same way as union? Personally, I would have this UnionToTuple
type as it is (possibly with additional comment in docs, that order could change). I use this type in my codebase and still find it useful.
Maybe just renaming this to UnionToUnsortedTuple
to indicate this is not sorted?
Yeah. I would go with UnionToUnorderedTuple
.
Bump :)
:+1:
hi @sindresorhus, @mkovel. I started refactoring this and discovered, that there are other conceptual problems with this type. Not sure what should be the correct result in this case
type T = UnionToUnsortedTuple<boolean | 'a'>; // [false, true, 'a']
There are many more issues & attempts to solve them here: https://github.com/microsoft/TypeScript/issues/13298 Not sure if we should have such a type in the library. TS should resolve this. What do you think?
@kopach Hi, honestly I didn't dive into it deeply. I just reused this code to solve the issue. Maybe it will be helpful.
export type UnionToIntersection<U> = (
U extends never ? never : (arg: U) => never
) extends (arg: infer I) => void
? I
: never;
export type UnionToTuple<T> = UnionToIntersection<
T extends never ? never : (t: T) => T
> extends (_: never) => infer W
? [...UnionToTuple<Exclude<T, W>>, W]
: [];
@kopach Hi, honestly I didn't dive into it deeply. I just reused this code to solve the issue. Maybe it will be helpful.
export type UnionToIntersection<U> = ( U extends never ? never : (arg: U) => never ) extends (arg: infer I) => void ? I : never; export type UnionToTuple<T> = UnionToIntersection< T extends never ? never : (t: T) => T > extends (_: never) => infer W ? [...UnionToTuple<Exclude<T, W>>, W] : [];
This is by far one of the most amazing types I've ever seen. It's exactly what I needed, and I don't really care much about the undefined behavior aspect. It's just for type checking and cli configuration.
Thank you so much.
I think it's still worth adding this type, but this PR is not moving forward, so closing for now: https://github.com/sindresorhus/type-fest/issues/819