Understanding how the compiler infers conditional types can be quite complex. It seems that there is a limit to how many type instantiations it will perform before defaulting to unknown
or any
. If you find that infer R
alone doesn't provide the desired result, consider creating your own method to analyze a type and determine the appropriate return value for R
.
In this scenario, let's define some basic types to get started on compiling...
// Hypothetical definitions
interface Entity<T> {
e: T;
}
class ArticleResource {
static getEntitySchema<T>(): Entity<T> {
return null!;
}
ar = "ArticleResource";
}
One potential implementation of SchemaOf<T>
could look like this:
type _SchemaOf<T> = T extends Entity<infer R>
? R
: T extends object ? { [K in keyof T]: _SchemaOf<T[K]> }[keyof T] : never;
(Named _SchemaOf
as it will be used to construct the final SchemaOf
). This logic checks if T
is simply an Entity<R>
, returning R
. If not, it attempts to recursively iterate through object properties to extract Entity
types and merge them into a union.
This function should ideally return what you expect - for example, _SchemaOf<Entity<A>>
yields A
, and
_SchemaOf<{a: X, b: Y, c: Z}>
results in
_SchemaOf<X> | _SchemaOf<Y> | _SchemaOf<Z>
, capturing all
Entity
instances within an object.
However, it may yield unexpected outcomes when provided with non-SchemaOne<T>
types, like {a: Entity<A>, b: string}
, which returns just A
. Therefore, a verification step is necessary:
type SchemaOf<T> = T extends SchemaOne<_SchemaOf<T>> ? _SchemaOf<T> : never;
This check ensures that the result from _SchemaOf<T>
aligns with
SchemaOne<_SchemaOf<T>>
. If not, the output is set to
never
.
To test these implementations:
type Z = SchemaOf<typeof a>;
// Expected output: ArticleResource
const b = { a: { b: sch } };
type ZZ = SchemaOf<typeof b>;
// Expected output: ArticleResource
const c = { a: { b: sch, c: "string" } };
type _C = _SchemaOf<typeof c>; // ArticleResource
type C = SchemaOf<typeof c>; // never
The above tests demonstrate the behavior of the implemented functions and ensure that they are functioning as intended. Hopefully, this provides some clarity and helps you progress. Good luck!
Link to code