For quite some time now, I've been on the quest to find a real-life example that isn't overly complex for this scenario. Let's see if this one fits the bill.
The context here relates to our usage of immer
, which provides a Draft
type structured as shown below (I have simplified it for better understanding):
type Draft<T> = T extends object ?
{
-readonly [K in keyof T]: Draft<T[K]>
}
: T
This particular type effectively removes the readonly
attribute from all object properties encountered, even when deeply nested.
However, everything works smoothly until we encounter an unresolved generic type denoted by T
. In such situations, it remains as Draft<T>
and is unable to be assigned values of type T
, which should ideally be feasible based on the type definition.
Hence, my query is: Is there a way to detect if a type is unresolved and return something different accordingly?
To illustrate, consider the following hypothetical situation:
type Draft<T> =
T is unresolved ?
T
: T extends object ?
{
-readonly [K in keyof T]: Draft<T[K]>
}
: T
I have set up an example that showcases this behavior on TypeScript playground.
In scenarios outside of the function, where T
is already resolved, everything functions perfectly. However, within the function scope, I face challenges calling a child function because it expects Draft<T>
while assuming that the argument T
provided is incompatible.
Yes, this may seem a bit contrived. If you prefer a practical example, check out this issue, where a conditional type over an unresolved generic leads to multiple forms being considered - ultimately resulting in incompatible function signatures. This highlights more than one instance where I am eager to uncover a solution to circumvent this TypeScript behavior :(