At the moment, TypeScript lacks a certain feature. Take a look at microsoft/TypeScript#23132 for more information on this missing feature. The status of this request is currently "awaiting more feedback." If you feel strongly about needing this feature, head over there, give it a 👍, and explain your specific use case in detail (it might require a bit more justification than what's provided here).
The underlying issue lies in the fact that when evaluating conditional types dependent on not-yet-specified generic type parameters, TypeScript doesn't take into account generic constraints. Instead, the evaluation is deferred. So even if T
is limited to string | number
, the compiler does not utilize this information to directly choose the true branch of CondType<T>
resulting in Box<T>
. It retains CondType<T>
, which may not be known as assignable to Box<T>
due to the unspecified nature of T
.
Potential workarounds until ms/TS#23132 is addressed:
Since CondType<T>
is guaranteed to evaluate to Box<T>
, you could simply use that type instead:
public three(param: Box<T>): void {
param; // Will be Box<T>
}
However, this workaround may not suit your actual needs. Keep in mind that any comments on ms/TS#23132 should highlight situations where such simple workarounds are not feasible.
A general-purpose workaround when you possess better insight into the type of an expression compared to the compiler is to employ type assertions. Essentially, you are assuming responsibility for verifying type safety instead of the compiler:
public four(param: CondType<T>): void {
const paramAsserted = param as Box<T>; // Simply assert it
}
This allows you to proceed as intended, but be cautious not to mislead the compiler. For instance, if you modify
class Test<T extends string | number>
to
class Test<T extends string | number | boolean>
later on, the type assertion will no longer hold true without triggering a compiler error. Therefore, exercise caution with type assertions and ensure they align with the actual situation.
Explore the code on the Playground