Repository navigation
Conversation
| //=> 0 | "a" | null | ['b', 1n] | (() => void) | {[x: string]: number; b: number} | ||
|
|
||
| expectType<SimplifiedUnion>({} as UnSimplifiedUnion); | ||
| // Checking all types are preserved. |
| @see {@link Simplify} | ||
| @category Union | ||
| */ | ||
| export type SimplifyUnion<Union> = {[Member in Union as typeof tag]: Member}[typeof tag]; |
There was a problem hiding this comment.
Doesn't seem to work if you pass the union directly instead of storing it in a type alias first.
type U1 = {a: 1};
type U2 = {b: 2};
type UnSimplifiedUnion = U1 | U2;
//=> U1 | U2 <- Not simplified
type SimplifiedUnion = SimplifyUnion<U1 | U2>;
//=> U1 | U2 <- Still, not simplifiedThere was a problem hiding this comment.
weird, i will look into that!
There was a problem hiding this comment.
@som-sm It seems the issue is that U1 and U2 aren’t unions themselves — they’re being recognized as standalone types.
type U1 = {a: 1};
declare const u1: U1;
// => Displays as `const u1: U1` instead of `const u1: {a: 1}`To properly demonstrate the effect, the example should use actual unions, as shown below:
type U1 = {a: 1} | {c: 3};
type U2 = {b: 2} | 'a';
type UnSimplifiedUnion = U1 | U2;
// => U1 | U2 (not simplified)
type SimplifiedUnion = SimplifyUnion<U1 | U2>;
// => {a: 1} | {c: 3} | {b: 2} | "a"There was a problem hiding this comment.
It seems the issue is that
U1andU2aren’t unions themselves
But U1 | U2 is a union, so it should work ideally.
The existing Simplify type that we have works:
type U1 = {a: 1};
type U2 = {b: 2};
type UnSimplifiedUnion = U1 | U2;
//=> U1 | U2 <- Not simplified
type SimplifiedUnion = Simplify<U1 | U2>;
//=> {a: 1} | {b: 2} <- Simplified@benzaria What problem does SimplifyUnion solve that Simplify doesn't? Is it just that the former handles functions and latter doesn't, if so, this should work:
type Simplify<T> = T extends Function ? T : {[P in keyof T]: T[P]};There was a problem hiding this comment.
Actually, my first attempt was the one below, which I originally made for #1178:
type Simplify<Type> = ConditionalSimplify<
Type,
NonRecursiveType | Set<unknown> | Map<unknown, unknown>,
object
>;It effectively does the same as your suggestion. However, what ended up happening is that some types depending on Simplify started to break — such as MergeDeep, ApplyDefaultOptions, and other types that rely on it.
That led me down a bit of a rabbit hole trying to fix MergeDeep and ApplyDefaultOptions. I was able to get ApplyDefaultOptions working again, but MergeDeep still needs a refactor, since it uses a fairly complex merge strategy for options instead of leveraging ApplyDefaultOptions.
My suggestion for now is to introduce both an internal and external version of Simplify, for better separation of use cases. This way, we can address the current limitation in Simplify without breaking half of the library:
export type _Simplify<T> = { [K in keyof T]: T[K] } & {};
export type Simplify<Type> = ConditionalSimplify<
Type,
NonRecursiveType | Set<unknown> | Map<unknown, unknown>,
object
>;@sindresorhus @som-sm What are your thoughts on this approach?
closes #1174