-
-
Notifications
You must be signed in to change notification settings - Fork 7
TypeScript 3.4+: Type instantiation is excessively deep and possibly infinite. #8
Comments
Maybe write codegen for something like that? type DeepFlatMap<Tuple> = Tuple extends any[]
? Tuple extends []
? []
: Tuple extends [any]
? Tuple["0"] extends any[]
? Tuple["0"] extends [any]
? Tuple["0"]["0"] extends any[]
? any // Tuple["0"]["0"] extends [any] // <-- need codegen
: Tuple["0"]["0"]
: any // Tuple["0"] extends [any, any] // <-- need codegen
: Tuple["0"]
: any // Tuple extends [any, any] // <-- need codegen
: never; |
You meant using a script to generate non-recursive type definition ahead of time? This requires a lot of work. And I am not exactly focusing on TypeScript projects right now. Is there any third-party tool that can help us? |
Yes, I mean generate type anotation for tuples like 20(breadth) x 5(depth) elements. |
It would be convenient to have a tool that reads a template file and generates a typescript file. But if there's none, I think writing scripts by hand is good enough. |
Can u add an example of template API? How u want to use it? |
I meant I don't want to use an API at all, just want to use a script to transform a template into TypeScript code. This code should work just fine: const UPPER_LIMIT = 100
typescript`
type UpperLimitRange = ${Array(UPPER_LIMIT).join(' | ')};
export type Repeat<T, N extends ${UPPER_LIMIT}> = ${
Array(UPPER_LIMIT)
.map((_, i) => i)
.map(n => `N extends ${n} ? [${Array(n).fill('T').join(', ')}]`)
.join(':\n')
};
` But I want it to be simpler, more elegant, and hygiene. Something like this (pseudo-code):
I want to find an existing tool for this. If there isn't one, then we must resort to the first code snippet. |
|
I have created microsoft/TypeScript#31619. For now, is there any other way around this? |
Thanks to this comment, I have a workaround: https://gist.github.com/KSXGitHub/a5c453c6212337f032adabb57b99062c @artalar My focus is not on any TypeScript project at the moment, can you help me with this? |
I dont get it, what |
The code that causes the error is one that has too many conditional types: type Foo<T extends 0 | 1 | 2 | 3 | ...> =
T extends 0 ? [] :
T extends 1 ? [0] :
T extends 2 ? [0, 1] :
T extends 3 ? [0, 1, 2] :
... By not using any conditional type, the error is eliminated: type Foo<T extends 0 | 1 | 2 | 3 | ...> = [
[],
[0],
[0, 1],
[0, 1, 2],
...
][T] |
Oops, I copied the wrong link. The link to the workaround is https://gist.github.com/KSXGitHub/a5c453c6212337f032adabb57b99062c |
Awesome! I can look at it closer few days later |
Tip: ts-morph seems to be cool. |
Hold on everybody I found a solution for 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 |
I wrote my own tuple like structure to replace the actual TypeScript tuple. It is very limited since I wrote for a specific use case but perhaps the idea could be extended into an actual library. https://github.com/maasglobal/scrapql/blob/master/src/tuple.ts |
Your "tuple" is an array in appearance but not in spirit, and if I was you, I would use objects instead. |
Using array is more convenient since it is easier to destructure type Stuff = Prepend<number, Prepend<string, Zero>>;
function foo( [ num, [ str ] ]: Stuff ) {
// ...
} |
PR microsoft/TypeScript#39094 will probably make fixing this a lot easier. |
Since TypeScript 3.4, it refuses to do recursive operation. Must fix it somehow.
The text was updated successfully, but these errors were encountered: