Is there a way to define a type that represents the widened version of another type?
Consider the following scenario:
function times<A extends number, B extends number>(a: A, b: B): A & B;
The intention behind this times
function is to preserve any extensions on types A
and B
, while the value itself becomes a * b
.
The issue arises when calling times(2, 3)
gives a return type of 2 & 3
, which is both inaccurate and unattainable. Instead of 6
, I neither want nor need it to be 2 & 3
; my desired output in this case should be number
.
Type widening typically happens automatically in Typescript through intricate rules. While it often causes confusion, in this particular instance, it's what I'm looking for but not getting. I seek a method to specify a return type of
WidenedVersionOf<A> & WidenedVersionOf<B>
. Is there a solution available for this requirement?
Addressing the anticipated question of "why not use composition?"
In this context, the extensions to number types hold significance. Although using a wrapper object with the value stored as a number and the extension separately kept would usually be the preferred approach, this situation differs. Our utilization involves branded primitives for units of measure (e.g., seconds, feet). These extensions exist exclusively in the type domain and do not manifest at runtime, offering several advantages.
We operate with a limited range of brandings (primarily In
, Per
, and
Delta</code), enabling constructions like <code>const v = 20 as number & In<'feet'> & Per<'second'>
or const d = 100 as number & In<'feet'> & Delta
). To accommodate all scenarios, the times
function incorporates numerous overloads. However, generic containers that store numbers of varying branding types using N extends number
encounter challenges with the overload of times
as described earlier. It is impractical (and likely impossible) to have each generic container handle every possible combination of In
, Per
, and/or Delta
cases individually.