When the Object.values(v) function is called, the compiler attempts to match the variable v
against a type of {[k: string]: T}
for a generic argument T
that it automatically infers (as per this call signature).
If v
has a type like {[k: string]: Z}
, then the compiler will infer T
as
Z</code, leading to successful compilation. However, if <code>v
is a
union of records such as
{[k: string]: X} | {[k: string]: Y}
, the inference process differs. The algorithm does not directly synthesize
X | Y
as the inferred type
T</code. Instead, it selects one candidate - let's say, <code>X
- and raises an error if
Record<string, X> | Record<string, Y>
cannot be assigned to
Record<string, X>
.
This intentional avoidance of synthesizing union types aims to prevent situations where every call would succeed, causing potential issues with mismatched types.
In your scenario, however, you desire this union inference. An open feature request at microsoft/TypeScript#44312 proposes a method to facilitate this inference, although it is not yet incorporated into the language.
Hence, relying on the compiler to directly infer the desired union type is not feasible.
Instead, we can explicitly specify the union type when calling Object.values()
, like so: Object.values<X | Y>(v)
. This means in your case, you could use
Object.values<number | boolean>(value)
and achieve the desired outcome.
However, hardcoding the type argument may not be ideal as you want it to dynamically adapt based on the type of value
. To compute the type X | Y
from a value such as
{[k: string]: X} | {[k: string]: Y}
, we can utilize
the typeof
type query operator paired with
indexed access types.
For example:
Object.values<typeof value[string]>(value); // okay
To summarize using a general example:
function foo() {
type A = Record<string, X>;
type B = Record;
function func(value: A | B) {
return Object.values(value);
}
// func(value: Record<string, X> | Record<string, Y>): (X | Y)[]
}
Within foo()
, the func()
function accepts a value of type A | B
and returns a value typed as (X | Y)[]
, without requiring manual specification of X | Y
. By employing typeof value[string]
, the compiler effectively calculates and utilizes the appropriate inferred union type.
Playground link to code