Skip to content

This is not for TypeScript but for everybody facing type instantiation too deep #34850

Closed
@aexol

Description

@aexol

Hold on everybody facing "Type instantiation is excessively deep and possibly infinite" I think I've just found a solution for type instantiation too deep error in
https://github.com/graphql-editor/graphql-zeus this repo. The solution is to create a conditional type even if you know that the type is the type. I can crawl out the rabbit hole now!

type Func<P extends any[], R> = (...args: P) => R;
type AnyFunc = Func<any, any>;

type IsType<M, T, Z, L> = T extends M ? Z : L;
type IsScalar<T, Z, L> = IsType<string | boolean | number, T, Z, L>;
type IsObject<T, Z, L> = IsType<{} | Record<string,any>, T, Z, L>;

type WithTypeNameValue<T> = T & {
  __typename?: true;
};

type AliasType<T> = WithTypeNameValue<T> & {
  __alias?: Record<string, WithTypeNameValue<T>>;
};

export type AliasedReturnType<T> = IsObject<T,{
  [P in keyof T]: T[P];
} &
Record<
  string,
  {
    [P in keyof T]: T[P];
  }
>,never>;

export type ResolverType<F> = F extends Func<infer P, any>
  ? P[0]
  : undefined;

type ArgsType<F extends AnyFunc> = F extends Func<infer P, any> ? P : never;
type OfType<T> = T extends Array<infer R> ? R : T;
type FirstArgument<F extends AnyFunc> = OfType<ArgsType<F>>;

interface GraphQLResponse {
  data?: Record<string, any>;
  errors?: Array<{
    message: string;
  }>;
}

export type State<T> = {
  [P in keyof T]?: T[P] extends (Array<infer R> | undefined)
    ? Array<AliasedReturnType<State<R>>>
    : T[P] extends AnyFunc
    ? AliasedReturnType<State<ReturnType<T[P]>>>
    : IsScalar<T[P], T[P], IsObject<T[P],AliasedReturnType<State<T[P]>>,never>>;
};

export type PlainObject<T> = {
  [P in keyof T]?: T[P] extends (Array<infer R> | undefined)
    ? Array<PlainObject<R>>
    : T[P] extends AnyFunc
    ?  PlainObject<ReturnType<T[P]>>
    : IsScalar<T[P], T[P], IsObject<T[P],PlainObject<T[P]>,never>>;
};

type ResolveValue<T> = T extends Array<infer R>
  ? SelectionSet<R>
  : T extends AnyFunc
  ? IsScalar<
      ReturnType<T>,
      [FirstArgument<T>],
      [FirstArgument<T>, SelectionSet<OfType<ReturnType<T>>>]
    >
  : IsScalar<T, T extends undefined ? undefined : true, IsObject<T,SelectionSet<T>,never>>;

export type SelectionSet<T> = IsScalar<
  T,  T extends undefined ? undefined : true
, IsObject<T,AliasType<
    {
      [P in keyof T]?: ResolveValue<T[P]>;
    }
  >,never>>;

type GraphQLReturner<T> = T extends Array<infer R> ? SelectionSet<R> : SelectionSet<T>;

type OperationToGraphQL<V,T> = (o: GraphQLReturner<V>) => Promise<AliasedReturnType<State<T>>>;

type ResolveApiField<T> = T extends Array<infer R>
  ? IsScalar<R, R, State<R>>
  : T extends AnyFunc
  ? IsScalar<OfType<ReturnType<T>>, T, State<OfType<ReturnType<T>>>>
  : IsScalar<T, T, State<T>>;

type ApiFieldToGraphQL<V,T> = (o: ResolveValue<V>) => Promise<ResolveApiField<T>>;

type fetchOptions = ArgsType<typeof fetch>;

So whats going on here? I had a problem with this error on large schemas, but... not anymore after adding IsObject type. The main thing is to drop the type in the type system as never even if you know it is a correct type. This is the only way as you tell the compiler that going down is conditional.

@orta can you look at it? Correct me if I am wrong but it looks like when the conditional types are closed somehow you can create very generic types.

Metadata

Metadata

Assignees

No one assigned

    Labels

    DiscussionIssues which may not have code impact

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions