While building the typesafe version of some library, I've run into the issue involving complex mapped types and got stuck.
Here's the simplified version of this issue. We have two "boxed" types - Strong<T>
and Weak<T>
, which can be thought of as "holding a value" and "possibly holding a value" correspondingly. Then, there is an object containing these "boxes", and I need to write a function which will unify it all into one large Strong
box holding an object, by converting Strong<T>
to required fields of type T
and Weak<T>
to optional fields of type T
. Later, in other part of the code, I'll "unbox" the type Strong<T>
to T
.
The problem is that I'm not able to make the fields conditionally optional. The code in question looks like this:
type Strong<T> = { __phantom?: T, marker: 'strong' };
type Weak<T> = { __phantom?: T, marker: 'weak' };
// helper functions, to be used later
function strong<T>(): Strong<T> {
return { marker: 'strong' };
}
function weak<T>(): Weak<T> {
return { marker: 'weak' };
}
// input type for my function
type Rec = { [index: string]: Strong<unknown> | Weak<unknown> };
// output type for my function; how to define it?
type Unified<T extends Rec> = { __phantom?: T, marker: 'unified' };
// put there something, just so that this type is unique
function unify<T extends Rec>(input: T): Strong<Unified<T>> {
// implementation is irrelevant now
return {} as any;
}
// when we have the Strong value, we can 'unbox' the type
type Unboxed<T> = T extends Strong<infer I> ? I : never;
// ...so, how to make this compile?
const unified = unify({ strong: strong<string>(), weak: weak<string>() });
const valid: Array<Unboxed<typeof unified>> = [{ strong: '' }, { strong: '', weak: '' }];
// ...and at the same time forbid this?
const invalid: Array<Unboxed<typeof unified>> = [{}, {weak: ''}, {unknown: ''}]
One attempt was to take the union of all object values, transforming them and then converting with UnionToIntersection
, but the type was complex enough for type inference to get stuck and spit out a bunch of unknown
s.
How can I define the Unified
type to be properly derived from the input?