Allow infer type variables to have constraints inferred (#32093)

* Allow `infer` type variables to have constraints infered and allow the breakdown of substitutes in simplifiable source inferences

* Still skip conditional inference when `extends infer Q` so such a pattern still acts as a constraint size breaker
This commit is contained in:
Wesley Wigham 2020-01-24 16:59:20 -08:00 committed by GitHub
parent 08e6bc20bb
commit 18cd79e179
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 966 additions and 2 deletions

View File

@ -12342,6 +12342,13 @@ namespace ts {
}
}
function unwrapSubstitution(type: Type): Type {
if (type.flags & TypeFlags.Substitution) {
return (type as SubstitutionType).substitute;
}
return type;
}
// Transform an indexed access to a simpler form, if possible. Return the simpler form, or return
// the type itself if no transformation is possible. The writing flag indicates that the type is
// the target of an assignment.
@ -12353,7 +12360,7 @@ namespace ts {
type[cache] = circularConstraintType;
// We recursively simplify the object type as it may in turn be an indexed access type. For example, with
// '{ [P in T]: { [Q in U]: number } }[T][U]' we want to first simplify the inner indexed access type.
const objectType = getSimplifiedType(type.objectType, writing);
const objectType = unwrapSubstitution(getSimplifiedType(type.objectType, writing));
const indexType = getSimplifiedType(type.indexType, writing);
// T[A | B] -> T[A] | T[B] (reading)
// T[A | B] -> T[A] & T[B] (writing)
@ -12531,7 +12538,11 @@ namespace ts {
let combinedMapper: TypeMapper | undefined;
if (root.inferTypeParameters) {
const context = createInferenceContext(root.inferTypeParameters, /*signature*/ undefined, InferenceFlags.None);
if (!checkTypeInstantiable) {
// We skip inference of the possible `infer` types unles the `extendsType` _is_ an infer type
// if it was, it's trivial to say that extendsType = checkType, however such a pattern is used to
// "reset" the type being build up during constraint calculation and avoid making an apparently "infinite" constraint
// so in those cases we refain from performing inference and retain the uninfered type parameter
if (!checkTypeInstantiable || !some(root.inferTypeParameters, t => t === extendsType)) {
// We don't want inferences from constraints as they may cause us to eagerly resolve the
// conditional type instead of deferring resolution. Also, we always want strict function
// types rules (i.e. proper contravariance) for inferences.
@ -17863,6 +17874,12 @@ namespace ts {
invokeOnce(source, target, inferFromObjectTypes);
}
}
if (source.flags & TypeFlags.Simplifiable) {
const simplified = getSimplifiedType(source, contravariant);
if (simplified !== source) {
inferFromTypes(simplified, target);
}
}
}
function inferWithPriority(source: Type, target: Type, newPriority: InferencePriority) {

View File

@ -0,0 +1,123 @@
//// [ramdaToolsNoInfinite.ts]
// All the following types are explained here:
// https://medium.freecodecamp.org/typescript-curry-ramda-types-f747e99744ab
// https://github.com/pirix-gh/medium/blob/master/types-curry-ramda/src/index.ts
declare namespace Tools {
type Head<T extends any[]> =
T extends [any, ...any[]]
? T[0]
: never;
type Tail<T extends any[]> =
((...t: T) => any) extends ((_: any, ...tail: infer TT) => any)
? TT
: [];
type HasTail<T extends any[]> =
T extends ([] | [any])
? false
: true;
type Last<T extends any[]> = {
0: Last<Tail<T>>;
1: Head<T>;
}[
HasTail<T> extends true
? 0
: 1
];
type Length<T extends any[]> =
T['length'];
type Prepend<E, T extends any[]> =
((head: E, ...args: T) => any) extends ((...args: infer U) => any)
? U
: T;
type Drop<N extends number, T extends any[], I extends any[] = []> = {
0: Drop<N, Tail<T>, Prepend<any, I>>;
1: T;
}[
Length<I> extends N
? 1
: 0
];
type Cast<X, Y> = X extends Y ? X : Y;
type Pos<I extends any[]> =
Length<I>;
type Next<I extends any[]> =
Prepend<any, I>;
type Prev<I extends any[]> =
Tail<I>;
type Iterator<Index extends number = 0, From extends any[] = [], I extends any[] = []> = {
0: Iterator<Index, Next<From>, Next<I>>;
1: From;
}[
Pos<I> extends Index
? 1
: 0
];
type Reverse<T extends any[], R extends any[] = [], I extends any[] = []> = {
0: Reverse<T, Prepend<T[Pos<I>], R>, Next<I>>;
1: R;
}[
Pos<I> extends Length<T>
? 1
: 0
];
type Concat<T1 extends any[], T2 extends any[]> =
Reverse<Reverse<T1> extends infer R ? Cast<R, any[]> : never, T2>;
type Append<E, T extends any[]> =
Concat<T, [E]>;
type ValueOfRecord<R> = R extends Record<any, infer T> ? T : never;
}
declare namespace R {
export type Placeholder = { __placeholder: void };
}
declare namespace Curry {
type GapOf<T1 extends any[], T2 extends any[], TN extends any[], I extends any[]> =
T1[Tools.Pos<I>] extends R.Placeholder
? Tools.Append<T2[Tools.Pos<I>], TN>
: TN;
interface GapsOfWorker<T1 extends any[], T2 extends any[], TN extends any[] = [], I extends any[] = []> {
0: GapsOf<T1, T2, GapOf<T1, T2, TN, I> extends infer G ? Tools.Cast<G, any[]> : never, Tools.Next<I>>;
1: Tools.Concat<TN, Tools.Drop<Tools.Pos<I>, T2> extends infer D ? Tools.Cast<D, any[]> : never>;
}
type GapsOf<T1 extends any[], T2 extends any[], TN extends any[] = [], I extends any[] = []> = GapsOfWorker<T1, T2, TN, I>[
Tools.Pos<I> extends Tools.Length<T1>
? 1
: 0
];
type PartialGaps<T extends any[]> = {
[K in keyof T]?: T[K] | R.Placeholder
};
type CleanedGaps<T extends any[]> = {
[K in keyof T]: NonNullable<T[K]>
};
type Gaps<T extends any[]> = CleanedGaps<PartialGaps<T>>;
type Curry<F extends ((...args: any) => any)> =
<T extends any[]>(...args: Tools.Cast<Tools.Cast<T, Gaps<Parameters<F>>>, any[]>) =>
GapsOf<T, Parameters<F>> extends [any, ...any[]]
? Curry<(...args: GapsOf<T, Parameters<F>> extends infer G ? Tools.Cast<G, any[]> : never) => ReturnType<F>>
: ReturnType<F>;
}
//// [ramdaToolsNoInfinite.js]

View File

@ -0,0 +1,431 @@
=== tests/cases/compiler/ramdaToolsNoInfinite.ts ===
// All the following types are explained here:
// https://medium.freecodecamp.org/typescript-curry-ramda-types-f747e99744ab
// https://github.com/pirix-gh/medium/blob/master/types-curry-ramda/src/index.ts
declare namespace Tools {
>Tools : Symbol(Tools, Decl(ramdaToolsNoInfinite.ts, 0, 0))
type Head<T extends any[]> =
>Head : Symbol(Head, Decl(ramdaToolsNoInfinite.ts, 3, 25))
>T : Symbol(T, Decl(ramdaToolsNoInfinite.ts, 4, 14))
T extends [any, ...any[]]
>T : Symbol(T, Decl(ramdaToolsNoInfinite.ts, 4, 14))
? T[0]
>T : Symbol(T, Decl(ramdaToolsNoInfinite.ts, 4, 14))
: never;
type Tail<T extends any[]> =
>Tail : Symbol(Tail, Decl(ramdaToolsNoInfinite.ts, 7, 16))
>T : Symbol(T, Decl(ramdaToolsNoInfinite.ts, 9, 14))
((...t: T) => any) extends ((_: any, ...tail: infer TT) => any)
>t : Symbol(t, Decl(ramdaToolsNoInfinite.ts, 10, 10))
>T : Symbol(T, Decl(ramdaToolsNoInfinite.ts, 9, 14))
>_ : Symbol(_, Decl(ramdaToolsNoInfinite.ts, 10, 37))
>tail : Symbol(tail, Decl(ramdaToolsNoInfinite.ts, 10, 44))
>TT : Symbol(TT, Decl(ramdaToolsNoInfinite.ts, 10, 59))
? TT
>TT : Symbol(TT, Decl(ramdaToolsNoInfinite.ts, 10, 59))
: [];
type HasTail<T extends any[]> =
>HasTail : Symbol(HasTail, Decl(ramdaToolsNoInfinite.ts, 12, 13))
>T : Symbol(T, Decl(ramdaToolsNoInfinite.ts, 14, 17))
T extends ([] | [any])
>T : Symbol(T, Decl(ramdaToolsNoInfinite.ts, 14, 17))
? false
: true;
type Last<T extends any[]> = {
>Last : Symbol(Last, Decl(ramdaToolsNoInfinite.ts, 17, 15))
>T : Symbol(T, Decl(ramdaToolsNoInfinite.ts, 19, 14))
0: Last<Tail<T>>;
>0 : Symbol(0, Decl(ramdaToolsNoInfinite.ts, 19, 34))
>Last : Symbol(Last, Decl(ramdaToolsNoInfinite.ts, 17, 15))
>Tail : Symbol(Tail, Decl(ramdaToolsNoInfinite.ts, 7, 16))
>T : Symbol(T, Decl(ramdaToolsNoInfinite.ts, 19, 14))
1: Head<T>;
>1 : Symbol(1, Decl(ramdaToolsNoInfinite.ts, 20, 25))
>Head : Symbol(Head, Decl(ramdaToolsNoInfinite.ts, 3, 25))
>T : Symbol(T, Decl(ramdaToolsNoInfinite.ts, 19, 14))
}[
HasTail<T> extends true
>HasTail : Symbol(HasTail, Decl(ramdaToolsNoInfinite.ts, 12, 13))
>T : Symbol(T, Decl(ramdaToolsNoInfinite.ts, 19, 14))
? 0
: 1
];
type Length<T extends any[]> =
>Length : Symbol(Length, Decl(ramdaToolsNoInfinite.ts, 26, 6))
>T : Symbol(T, Decl(ramdaToolsNoInfinite.ts, 28, 16))
T['length'];
>T : Symbol(T, Decl(ramdaToolsNoInfinite.ts, 28, 16))
type Prepend<E, T extends any[]> =
>Prepend : Symbol(Prepend, Decl(ramdaToolsNoInfinite.ts, 29, 20))
>E : Symbol(E, Decl(ramdaToolsNoInfinite.ts, 31, 17))
>T : Symbol(T, Decl(ramdaToolsNoInfinite.ts, 31, 19))
((head: E, ...args: T) => any) extends ((...args: infer U) => any)
>head : Symbol(head, Decl(ramdaToolsNoInfinite.ts, 32, 10))
>E : Symbol(E, Decl(ramdaToolsNoInfinite.ts, 31, 17))
>args : Symbol(args, Decl(ramdaToolsNoInfinite.ts, 32, 18))
>T : Symbol(T, Decl(ramdaToolsNoInfinite.ts, 31, 19))
>args : Symbol(args, Decl(ramdaToolsNoInfinite.ts, 32, 49))
>U : Symbol(U, Decl(ramdaToolsNoInfinite.ts, 32, 63))
? U
>U : Symbol(U, Decl(ramdaToolsNoInfinite.ts, 32, 63))
: T;
>T : Symbol(T, Decl(ramdaToolsNoInfinite.ts, 31, 19))
type Drop<N extends number, T extends any[], I extends any[] = []> = {
>Drop : Symbol(Drop, Decl(ramdaToolsNoInfinite.ts, 34, 12))
>N : Symbol(N, Decl(ramdaToolsNoInfinite.ts, 36, 14))
>T : Symbol(T, Decl(ramdaToolsNoInfinite.ts, 36, 31))
>I : Symbol(I, Decl(ramdaToolsNoInfinite.ts, 36, 48))
0: Drop<N, Tail<T>, Prepend<any, I>>;
>0 : Symbol(0, Decl(ramdaToolsNoInfinite.ts, 36, 74))
>Drop : Symbol(Drop, Decl(ramdaToolsNoInfinite.ts, 34, 12))
>N : Symbol(N, Decl(ramdaToolsNoInfinite.ts, 36, 14))
>Tail : Symbol(Tail, Decl(ramdaToolsNoInfinite.ts, 7, 16))
>T : Symbol(T, Decl(ramdaToolsNoInfinite.ts, 36, 31))
>Prepend : Symbol(Prepend, Decl(ramdaToolsNoInfinite.ts, 29, 20))
>I : Symbol(I, Decl(ramdaToolsNoInfinite.ts, 36, 48))
1: T;
>1 : Symbol(1, Decl(ramdaToolsNoInfinite.ts, 37, 45))
>T : Symbol(T, Decl(ramdaToolsNoInfinite.ts, 36, 31))
}[
Length<I> extends N
>Length : Symbol(Length, Decl(ramdaToolsNoInfinite.ts, 26, 6))
>I : Symbol(I, Decl(ramdaToolsNoInfinite.ts, 36, 48))
>N : Symbol(N, Decl(ramdaToolsNoInfinite.ts, 36, 14))
? 1
: 0
];
type Cast<X, Y> = X extends Y ? X : Y;
>Cast : Symbol(Cast, Decl(ramdaToolsNoInfinite.ts, 43, 6))
>X : Symbol(X, Decl(ramdaToolsNoInfinite.ts, 45, 14))
>Y : Symbol(Y, Decl(ramdaToolsNoInfinite.ts, 45, 16))
>X : Symbol(X, Decl(ramdaToolsNoInfinite.ts, 45, 14))
>Y : Symbol(Y, Decl(ramdaToolsNoInfinite.ts, 45, 16))
>X : Symbol(X, Decl(ramdaToolsNoInfinite.ts, 45, 14))
>Y : Symbol(Y, Decl(ramdaToolsNoInfinite.ts, 45, 16))
type Pos<I extends any[]> =
>Pos : Symbol(Pos, Decl(ramdaToolsNoInfinite.ts, 45, 42))
>I : Symbol(I, Decl(ramdaToolsNoInfinite.ts, 47, 13))
Length<I>;
>Length : Symbol(Length, Decl(ramdaToolsNoInfinite.ts, 26, 6))
>I : Symbol(I, Decl(ramdaToolsNoInfinite.ts, 47, 13))
type Next<I extends any[]> =
>Next : Symbol(Next, Decl(ramdaToolsNoInfinite.ts, 48, 18))
>I : Symbol(I, Decl(ramdaToolsNoInfinite.ts, 50, 14))
Prepend<any, I>;
>Prepend : Symbol(Prepend, Decl(ramdaToolsNoInfinite.ts, 29, 20))
>I : Symbol(I, Decl(ramdaToolsNoInfinite.ts, 50, 14))
type Prev<I extends any[]> =
>Prev : Symbol(Prev, Decl(ramdaToolsNoInfinite.ts, 51, 24))
>I : Symbol(I, Decl(ramdaToolsNoInfinite.ts, 53, 14))
Tail<I>;
>Tail : Symbol(Tail, Decl(ramdaToolsNoInfinite.ts, 7, 16))
>I : Symbol(I, Decl(ramdaToolsNoInfinite.ts, 53, 14))
type Iterator<Index extends number = 0, From extends any[] = [], I extends any[] = []> = {
>Iterator : Symbol(Iterator, Decl(ramdaToolsNoInfinite.ts, 54, 16))
>Index : Symbol(Index, Decl(ramdaToolsNoInfinite.ts, 56, 18))
>From : Symbol(From, Decl(ramdaToolsNoInfinite.ts, 56, 43))
>I : Symbol(I, Decl(ramdaToolsNoInfinite.ts, 56, 68))
0: Iterator<Index, Next<From>, Next<I>>;
>0 : Symbol(0, Decl(ramdaToolsNoInfinite.ts, 56, 94))
>Iterator : Symbol(Iterator, Decl(ramdaToolsNoInfinite.ts, 54, 16))
>Index : Symbol(Index, Decl(ramdaToolsNoInfinite.ts, 56, 18))
>Next : Symbol(Next, Decl(ramdaToolsNoInfinite.ts, 48, 18))
>From : Symbol(From, Decl(ramdaToolsNoInfinite.ts, 56, 43))
>Next : Symbol(Next, Decl(ramdaToolsNoInfinite.ts, 48, 18))
>I : Symbol(I, Decl(ramdaToolsNoInfinite.ts, 56, 68))
1: From;
>1 : Symbol(1, Decl(ramdaToolsNoInfinite.ts, 57, 48))
>From : Symbol(From, Decl(ramdaToolsNoInfinite.ts, 56, 43))
}[
Pos<I> extends Index
>Pos : Symbol(Pos, Decl(ramdaToolsNoInfinite.ts, 45, 42))
>I : Symbol(I, Decl(ramdaToolsNoInfinite.ts, 56, 68))
>Index : Symbol(Index, Decl(ramdaToolsNoInfinite.ts, 56, 18))
? 1
: 0
];
type Reverse<T extends any[], R extends any[] = [], I extends any[] = []> = {
>Reverse : Symbol(Reverse, Decl(ramdaToolsNoInfinite.ts, 63, 6))
>T : Symbol(T, Decl(ramdaToolsNoInfinite.ts, 65, 17))
>R : Symbol(R, Decl(ramdaToolsNoInfinite.ts, 65, 33))
>I : Symbol(I, Decl(ramdaToolsNoInfinite.ts, 65, 55))
0: Reverse<T, Prepend<T[Pos<I>], R>, Next<I>>;
>0 : Symbol(0, Decl(ramdaToolsNoInfinite.ts, 65, 81))
>Reverse : Symbol(Reverse, Decl(ramdaToolsNoInfinite.ts, 63, 6))
>T : Symbol(T, Decl(ramdaToolsNoInfinite.ts, 65, 17))
>Prepend : Symbol(Prepend, Decl(ramdaToolsNoInfinite.ts, 29, 20))
>T : Symbol(T, Decl(ramdaToolsNoInfinite.ts, 65, 17))
>Pos : Symbol(Pos, Decl(ramdaToolsNoInfinite.ts, 45, 42))
>I : Symbol(I, Decl(ramdaToolsNoInfinite.ts, 65, 55))
>R : Symbol(R, Decl(ramdaToolsNoInfinite.ts, 65, 33))
>Next : Symbol(Next, Decl(ramdaToolsNoInfinite.ts, 48, 18))
>I : Symbol(I, Decl(ramdaToolsNoInfinite.ts, 65, 55))
1: R;
>1 : Symbol(1, Decl(ramdaToolsNoInfinite.ts, 66, 54))
>R : Symbol(R, Decl(ramdaToolsNoInfinite.ts, 65, 33))
}[
Pos<I> extends Length<T>
>Pos : Symbol(Pos, Decl(ramdaToolsNoInfinite.ts, 45, 42))
>I : Symbol(I, Decl(ramdaToolsNoInfinite.ts, 65, 55))
>Length : Symbol(Length, Decl(ramdaToolsNoInfinite.ts, 26, 6))
>T : Symbol(T, Decl(ramdaToolsNoInfinite.ts, 65, 17))
? 1
: 0
];
type Concat<T1 extends any[], T2 extends any[]> =
>Concat : Symbol(Concat, Decl(ramdaToolsNoInfinite.ts, 72, 6))
>T1 : Symbol(T1, Decl(ramdaToolsNoInfinite.ts, 74, 16))
>T2 : Symbol(T2, Decl(ramdaToolsNoInfinite.ts, 74, 33))
Reverse<Reverse<T1> extends infer R ? Cast<R, any[]> : never, T2>;
>Reverse : Symbol(Reverse, Decl(ramdaToolsNoInfinite.ts, 63, 6))
>Reverse : Symbol(Reverse, Decl(ramdaToolsNoInfinite.ts, 63, 6))
>T1 : Symbol(T1, Decl(ramdaToolsNoInfinite.ts, 74, 16))
>R : Symbol(R, Decl(ramdaToolsNoInfinite.ts, 75, 41))
>Cast : Symbol(Cast, Decl(ramdaToolsNoInfinite.ts, 43, 6))
>R : Symbol(R, Decl(ramdaToolsNoInfinite.ts, 75, 41))
>T2 : Symbol(T2, Decl(ramdaToolsNoInfinite.ts, 74, 33))
type Append<E, T extends any[]> =
>Append : Symbol(Append, Decl(ramdaToolsNoInfinite.ts, 75, 74))
>E : Symbol(E, Decl(ramdaToolsNoInfinite.ts, 77, 16))
>T : Symbol(T, Decl(ramdaToolsNoInfinite.ts, 77, 18))
Concat<T, [E]>;
>Concat : Symbol(Concat, Decl(ramdaToolsNoInfinite.ts, 72, 6))
>T : Symbol(T, Decl(ramdaToolsNoInfinite.ts, 77, 18))
>E : Symbol(E, Decl(ramdaToolsNoInfinite.ts, 77, 16))
type ValueOfRecord<R> = R extends Record<any, infer T> ? T : never;
>ValueOfRecord : Symbol(ValueOfRecord, Decl(ramdaToolsNoInfinite.ts, 78, 23))
>R : Symbol(R, Decl(ramdaToolsNoInfinite.ts, 80, 23))
>R : Symbol(R, Decl(ramdaToolsNoInfinite.ts, 80, 23))
>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --))
>T : Symbol(T, Decl(ramdaToolsNoInfinite.ts, 80, 55))
>T : Symbol(T, Decl(ramdaToolsNoInfinite.ts, 80, 55))
}
declare namespace R {
>R : Symbol(R, Decl(ramdaToolsNoInfinite.ts, 81, 1))
export type Placeholder = { __placeholder: void };
>Placeholder : Symbol(Placeholder, Decl(ramdaToolsNoInfinite.ts, 83, 21))
>__placeholder : Symbol(__placeholder, Decl(ramdaToolsNoInfinite.ts, 84, 31))
}
declare namespace Curry {
>Curry : Symbol(Curry, Decl(ramdaToolsNoInfinite.ts, 85, 1))
type GapOf<T1 extends any[], T2 extends any[], TN extends any[], I extends any[]> =
>GapOf : Symbol(GapOf, Decl(ramdaToolsNoInfinite.ts, 87, 25))
>T1 : Symbol(T1, Decl(ramdaToolsNoInfinite.ts, 88, 15))
>T2 : Symbol(T2, Decl(ramdaToolsNoInfinite.ts, 88, 32))
>TN : Symbol(TN, Decl(ramdaToolsNoInfinite.ts, 88, 50))
>I : Symbol(I, Decl(ramdaToolsNoInfinite.ts, 88, 68))
T1[Tools.Pos<I>] extends R.Placeholder
>T1 : Symbol(T1, Decl(ramdaToolsNoInfinite.ts, 88, 15))
>Tools : Symbol(Tools, Decl(ramdaToolsNoInfinite.ts, 0, 0))
>Pos : Symbol(Tools.Pos, Decl(ramdaToolsNoInfinite.ts, 45, 42))
>I : Symbol(I, Decl(ramdaToolsNoInfinite.ts, 88, 68))
>R : Symbol(R, Decl(ramdaToolsNoInfinite.ts, 81, 1))
>Placeholder : Symbol(R.Placeholder, Decl(ramdaToolsNoInfinite.ts, 83, 21))
? Tools.Append<T2[Tools.Pos<I>], TN>
>Tools : Symbol(Tools, Decl(ramdaToolsNoInfinite.ts, 0, 0))
>Append : Symbol(Tools.Append, Decl(ramdaToolsNoInfinite.ts, 75, 74))
>T2 : Symbol(T2, Decl(ramdaToolsNoInfinite.ts, 88, 32))
>Tools : Symbol(Tools, Decl(ramdaToolsNoInfinite.ts, 0, 0))
>Pos : Symbol(Tools.Pos, Decl(ramdaToolsNoInfinite.ts, 45, 42))
>I : Symbol(I, Decl(ramdaToolsNoInfinite.ts, 88, 68))
>TN : Symbol(TN, Decl(ramdaToolsNoInfinite.ts, 88, 50))
: TN;
>TN : Symbol(TN, Decl(ramdaToolsNoInfinite.ts, 88, 50))
interface GapsOfWorker<T1 extends any[], T2 extends any[], TN extends any[] = [], I extends any[] = []> {
>GapsOfWorker : Symbol(GapsOfWorker, Decl(ramdaToolsNoInfinite.ts, 91, 13))
>T1 : Symbol(T1, Decl(ramdaToolsNoInfinite.ts, 93, 27))
>T2 : Symbol(T2, Decl(ramdaToolsNoInfinite.ts, 93, 44))
>TN : Symbol(TN, Decl(ramdaToolsNoInfinite.ts, 93, 62))
>I : Symbol(I, Decl(ramdaToolsNoInfinite.ts, 93, 85))
0: GapsOf<T1, T2, GapOf<T1, T2, TN, I> extends infer G ? Tools.Cast<G, any[]> : never, Tools.Next<I>>;
>0 : Symbol(GapsOfWorker[0], Decl(ramdaToolsNoInfinite.ts, 93, 109))
>GapsOf : Symbol(GapsOf, Decl(ramdaToolsNoInfinite.ts, 96, 5))
>T1 : Symbol(T1, Decl(ramdaToolsNoInfinite.ts, 93, 27))
>T2 : Symbol(T2, Decl(ramdaToolsNoInfinite.ts, 93, 44))
>GapOf : Symbol(GapOf, Decl(ramdaToolsNoInfinite.ts, 87, 25))
>T1 : Symbol(T1, Decl(ramdaToolsNoInfinite.ts, 93, 27))
>T2 : Symbol(T2, Decl(ramdaToolsNoInfinite.ts, 93, 44))
>TN : Symbol(TN, Decl(ramdaToolsNoInfinite.ts, 93, 62))
>I : Symbol(I, Decl(ramdaToolsNoInfinite.ts, 93, 85))
>G : Symbol(G, Decl(ramdaToolsNoInfinite.ts, 94, 60))
>Tools : Symbol(Tools, Decl(ramdaToolsNoInfinite.ts, 0, 0))
>Cast : Symbol(Tools.Cast, Decl(ramdaToolsNoInfinite.ts, 43, 6))
>G : Symbol(G, Decl(ramdaToolsNoInfinite.ts, 94, 60))
>Tools : Symbol(Tools, Decl(ramdaToolsNoInfinite.ts, 0, 0))
>Next : Symbol(Tools.Next, Decl(ramdaToolsNoInfinite.ts, 48, 18))
>I : Symbol(I, Decl(ramdaToolsNoInfinite.ts, 93, 85))
1: Tools.Concat<TN, Tools.Drop<Tools.Pos<I>, T2> extends infer D ? Tools.Cast<D, any[]> : never>;
>1 : Symbol(GapsOfWorker[1], Decl(ramdaToolsNoInfinite.ts, 94, 110))
>Tools : Symbol(Tools, Decl(ramdaToolsNoInfinite.ts, 0, 0))
>Concat : Symbol(Tools.Concat, Decl(ramdaToolsNoInfinite.ts, 72, 6))
>TN : Symbol(TN, Decl(ramdaToolsNoInfinite.ts, 93, 62))
>Tools : Symbol(Tools, Decl(ramdaToolsNoInfinite.ts, 0, 0))
>Drop : Symbol(Tools.Drop, Decl(ramdaToolsNoInfinite.ts, 34, 12))
>Tools : Symbol(Tools, Decl(ramdaToolsNoInfinite.ts, 0, 0))
>Pos : Symbol(Tools.Pos, Decl(ramdaToolsNoInfinite.ts, 45, 42))
>I : Symbol(I, Decl(ramdaToolsNoInfinite.ts, 93, 85))
>T2 : Symbol(T2, Decl(ramdaToolsNoInfinite.ts, 93, 44))
>D : Symbol(D, Decl(ramdaToolsNoInfinite.ts, 95, 70))
>Tools : Symbol(Tools, Decl(ramdaToolsNoInfinite.ts, 0, 0))
>Cast : Symbol(Tools.Cast, Decl(ramdaToolsNoInfinite.ts, 43, 6))
>D : Symbol(D, Decl(ramdaToolsNoInfinite.ts, 95, 70))
}
type GapsOf<T1 extends any[], T2 extends any[], TN extends any[] = [], I extends any[] = []> = GapsOfWorker<T1, T2, TN, I>[
>GapsOf : Symbol(GapsOf, Decl(ramdaToolsNoInfinite.ts, 96, 5))
>T1 : Symbol(T1, Decl(ramdaToolsNoInfinite.ts, 97, 16))
>T2 : Symbol(T2, Decl(ramdaToolsNoInfinite.ts, 97, 33))
>TN : Symbol(TN, Decl(ramdaToolsNoInfinite.ts, 97, 51))
>I : Symbol(I, Decl(ramdaToolsNoInfinite.ts, 97, 74))
>GapsOfWorker : Symbol(GapsOfWorker, Decl(ramdaToolsNoInfinite.ts, 91, 13))
>T1 : Symbol(T1, Decl(ramdaToolsNoInfinite.ts, 97, 16))
>T2 : Symbol(T2, Decl(ramdaToolsNoInfinite.ts, 97, 33))
>TN : Symbol(TN, Decl(ramdaToolsNoInfinite.ts, 97, 51))
>I : Symbol(I, Decl(ramdaToolsNoInfinite.ts, 97, 74))
Tools.Pos<I> extends Tools.Length<T1>
>Tools : Symbol(Tools, Decl(ramdaToolsNoInfinite.ts, 0, 0))
>Pos : Symbol(Tools.Pos, Decl(ramdaToolsNoInfinite.ts, 45, 42))
>I : Symbol(I, Decl(ramdaToolsNoInfinite.ts, 97, 74))
>Tools : Symbol(Tools, Decl(ramdaToolsNoInfinite.ts, 0, 0))
>Length : Symbol(Tools.Length, Decl(ramdaToolsNoInfinite.ts, 26, 6))
>T1 : Symbol(T1, Decl(ramdaToolsNoInfinite.ts, 97, 16))
? 1
: 0
];
type PartialGaps<T extends any[]> = {
>PartialGaps : Symbol(PartialGaps, Decl(ramdaToolsNoInfinite.ts, 101, 6))
>T : Symbol(T, Decl(ramdaToolsNoInfinite.ts, 103, 21))
[K in keyof T]?: T[K] | R.Placeholder
>K : Symbol(K, Decl(ramdaToolsNoInfinite.ts, 104, 9))
>T : Symbol(T, Decl(ramdaToolsNoInfinite.ts, 103, 21))
>T : Symbol(T, Decl(ramdaToolsNoInfinite.ts, 103, 21))
>K : Symbol(K, Decl(ramdaToolsNoInfinite.ts, 104, 9))
>R : Symbol(R, Decl(ramdaToolsNoInfinite.ts, 81, 1))
>Placeholder : Symbol(R.Placeholder, Decl(ramdaToolsNoInfinite.ts, 83, 21))
};
type CleanedGaps<T extends any[]> = {
>CleanedGaps : Symbol(CleanedGaps, Decl(ramdaToolsNoInfinite.ts, 105, 6))
>T : Symbol(T, Decl(ramdaToolsNoInfinite.ts, 107, 21))
[K in keyof T]: NonNullable<T[K]>
>K : Symbol(K, Decl(ramdaToolsNoInfinite.ts, 108, 9))
>T : Symbol(T, Decl(ramdaToolsNoInfinite.ts, 107, 21))
>NonNullable : Symbol(NonNullable, Decl(lib.es5.d.ts, --, --))
>T : Symbol(T, Decl(ramdaToolsNoInfinite.ts, 107, 21))
>K : Symbol(K, Decl(ramdaToolsNoInfinite.ts, 108, 9))
};
type Gaps<T extends any[]> = CleanedGaps<PartialGaps<T>>;
>Gaps : Symbol(Gaps, Decl(ramdaToolsNoInfinite.ts, 109, 6))
>T : Symbol(T, Decl(ramdaToolsNoInfinite.ts, 111, 14))
>CleanedGaps : Symbol(CleanedGaps, Decl(ramdaToolsNoInfinite.ts, 105, 6))
>PartialGaps : Symbol(PartialGaps, Decl(ramdaToolsNoInfinite.ts, 101, 6))
>T : Symbol(T, Decl(ramdaToolsNoInfinite.ts, 111, 14))
type Curry<F extends ((...args: any) => any)> =
>Curry : Symbol(Curry, Decl(ramdaToolsNoInfinite.ts, 111, 61))
>F : Symbol(F, Decl(ramdaToolsNoInfinite.ts, 113, 15))
>args : Symbol(args, Decl(ramdaToolsNoInfinite.ts, 113, 27))
<T extends any[]>(...args: Tools.Cast<Tools.Cast<T, Gaps<Parameters<F>>>, any[]>) =>
>T : Symbol(T, Decl(ramdaToolsNoInfinite.ts, 114, 9))
>args : Symbol(args, Decl(ramdaToolsNoInfinite.ts, 114, 26))
>Tools : Symbol(Tools, Decl(ramdaToolsNoInfinite.ts, 0, 0))
>Cast : Symbol(Tools.Cast, Decl(ramdaToolsNoInfinite.ts, 43, 6))
>Tools : Symbol(Tools, Decl(ramdaToolsNoInfinite.ts, 0, 0))
>Cast : Symbol(Tools.Cast, Decl(ramdaToolsNoInfinite.ts, 43, 6))
>T : Symbol(T, Decl(ramdaToolsNoInfinite.ts, 114, 9))
>Gaps : Symbol(Gaps, Decl(ramdaToolsNoInfinite.ts, 109, 6))
>Parameters : Symbol(Parameters, Decl(lib.es5.d.ts, --, --))
>F : Symbol(F, Decl(ramdaToolsNoInfinite.ts, 113, 15))
GapsOf<T, Parameters<F>> extends [any, ...any[]]
>GapsOf : Symbol(GapsOf, Decl(ramdaToolsNoInfinite.ts, 96, 5))
>T : Symbol(T, Decl(ramdaToolsNoInfinite.ts, 114, 9))
>Parameters : Symbol(Parameters, Decl(lib.es5.d.ts, --, --))
>F : Symbol(F, Decl(ramdaToolsNoInfinite.ts, 113, 15))
? Curry<(...args: GapsOf<T, Parameters<F>> extends infer G ? Tools.Cast<G, any[]> : never) => ReturnType<F>>
>Curry : Symbol(Curry, Decl(ramdaToolsNoInfinite.ts, 111, 61))
>args : Symbol(args, Decl(ramdaToolsNoInfinite.ts, 116, 21))
>GapsOf : Symbol(GapsOf, Decl(ramdaToolsNoInfinite.ts, 96, 5))
>T : Symbol(T, Decl(ramdaToolsNoInfinite.ts, 114, 9))
>Parameters : Symbol(Parameters, Decl(lib.es5.d.ts, --, --))
>F : Symbol(F, Decl(ramdaToolsNoInfinite.ts, 113, 15))
>G : Symbol(G, Decl(ramdaToolsNoInfinite.ts, 116, 68))
>Tools : Symbol(Tools, Decl(ramdaToolsNoInfinite.ts, 0, 0))
>Cast : Symbol(Tools.Cast, Decl(ramdaToolsNoInfinite.ts, 43, 6))
>G : Symbol(G, Decl(ramdaToolsNoInfinite.ts, 116, 68))
>ReturnType : Symbol(ReturnType, Decl(lib.es5.d.ts, --, --))
>F : Symbol(F, Decl(ramdaToolsNoInfinite.ts, 113, 15))
: ReturnType<F>;
>ReturnType : Symbol(ReturnType, Decl(lib.es5.d.ts, --, --))
>F : Symbol(F, Decl(ramdaToolsNoInfinite.ts, 113, 15))
}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,8 @@
//// [substituteReturnTypeSatisfiesConstraint.ts]
type M = { p: string };
type O = { m: () => M };
type X<T extends M> = T;
type FFG<T> = T extends O ? X<ReturnType<T['m']>> : never; // error!
//// [substituteReturnTypeSatisfiesConstraint.js]

View File

@ -0,0 +1,25 @@
=== tests/cases/compiler/substituteReturnTypeSatisfiesConstraint.ts ===
type M = { p: string };
>M : Symbol(M, Decl(substituteReturnTypeSatisfiesConstraint.ts, 0, 0))
>p : Symbol(p, Decl(substituteReturnTypeSatisfiesConstraint.ts, 0, 10))
type O = { m: () => M };
>O : Symbol(O, Decl(substituteReturnTypeSatisfiesConstraint.ts, 0, 23))
>m : Symbol(m, Decl(substituteReturnTypeSatisfiesConstraint.ts, 1, 10))
>M : Symbol(M, Decl(substituteReturnTypeSatisfiesConstraint.ts, 0, 0))
type X<T extends M> = T;
>X : Symbol(X, Decl(substituteReturnTypeSatisfiesConstraint.ts, 1, 24))
>T : Symbol(T, Decl(substituteReturnTypeSatisfiesConstraint.ts, 2, 7))
>M : Symbol(M, Decl(substituteReturnTypeSatisfiesConstraint.ts, 0, 0))
>T : Symbol(T, Decl(substituteReturnTypeSatisfiesConstraint.ts, 2, 7))
type FFG<T> = T extends O ? X<ReturnType<T['m']>> : never; // error!
>FFG : Symbol(FFG, Decl(substituteReturnTypeSatisfiesConstraint.ts, 2, 24))
>T : Symbol(T, Decl(substituteReturnTypeSatisfiesConstraint.ts, 3, 9))
>T : Symbol(T, Decl(substituteReturnTypeSatisfiesConstraint.ts, 3, 9))
>O : Symbol(O, Decl(substituteReturnTypeSatisfiesConstraint.ts, 0, 23))
>X : Symbol(X, Decl(substituteReturnTypeSatisfiesConstraint.ts, 1, 24))
>ReturnType : Symbol(ReturnType, Decl(lib.es5.d.ts, --, --))
>T : Symbol(T, Decl(substituteReturnTypeSatisfiesConstraint.ts, 3, 9))

View File

@ -0,0 +1,15 @@
=== tests/cases/compiler/substituteReturnTypeSatisfiesConstraint.ts ===
type M = { p: string };
>M : M
>p : string
type O = { m: () => M };
>O : O
>m : () => M
type X<T extends M> = T;
>X : T
type FFG<T> = T extends O ? X<ReturnType<T['m']>> : never; // error!
>FFG : FFG<T>

View File

@ -0,0 +1,120 @@
// All the following types are explained here:
// https://medium.freecodecamp.org/typescript-curry-ramda-types-f747e99744ab
// https://github.com/pirix-gh/medium/blob/master/types-curry-ramda/src/index.ts
declare namespace Tools {
type Head<T extends any[]> =
T extends [any, ...any[]]
? T[0]
: never;
type Tail<T extends any[]> =
((...t: T) => any) extends ((_: any, ...tail: infer TT) => any)
? TT
: [];
type HasTail<T extends any[]> =
T extends ([] | [any])
? false
: true;
type Last<T extends any[]> = {
0: Last<Tail<T>>;
1: Head<T>;
}[
HasTail<T> extends true
? 0
: 1
];
type Length<T extends any[]> =
T['length'];
type Prepend<E, T extends any[]> =
((head: E, ...args: T) => any) extends ((...args: infer U) => any)
? U
: T;
type Drop<N extends number, T extends any[], I extends any[] = []> = {
0: Drop<N, Tail<T>, Prepend<any, I>>;
1: T;
}[
Length<I> extends N
? 1
: 0
];
type Cast<X, Y> = X extends Y ? X : Y;
type Pos<I extends any[]> =
Length<I>;
type Next<I extends any[]> =
Prepend<any, I>;
type Prev<I extends any[]> =
Tail<I>;
type Iterator<Index extends number = 0, From extends any[] = [], I extends any[] = []> = {
0: Iterator<Index, Next<From>, Next<I>>;
1: From;
}[
Pos<I> extends Index
? 1
: 0
];
type Reverse<T extends any[], R extends any[] = [], I extends any[] = []> = {
0: Reverse<T, Prepend<T[Pos<I>], R>, Next<I>>;
1: R;
}[
Pos<I> extends Length<T>
? 1
: 0
];
type Concat<T1 extends any[], T2 extends any[]> =
Reverse<Reverse<T1> extends infer R ? Cast<R, any[]> : never, T2>;
type Append<E, T extends any[]> =
Concat<T, [E]>;
type ValueOfRecord<R> = R extends Record<any, infer T> ? T : never;
}
declare namespace R {
export type Placeholder = { __placeholder: void };
}
declare namespace Curry {
type GapOf<T1 extends any[], T2 extends any[], TN extends any[], I extends any[]> =
T1[Tools.Pos<I>] extends R.Placeholder
? Tools.Append<T2[Tools.Pos<I>], TN>
: TN;
interface GapsOfWorker<T1 extends any[], T2 extends any[], TN extends any[] = [], I extends any[] = []> {
0: GapsOf<T1, T2, GapOf<T1, T2, TN, I> extends infer G ? Tools.Cast<G, any[]> : never, Tools.Next<I>>;
1: Tools.Concat<TN, Tools.Drop<Tools.Pos<I>, T2> extends infer D ? Tools.Cast<D, any[]> : never>;
}
type GapsOf<T1 extends any[], T2 extends any[], TN extends any[] = [], I extends any[] = []> = GapsOfWorker<T1, T2, TN, I>[
Tools.Pos<I> extends Tools.Length<T1>
? 1
: 0
];
type PartialGaps<T extends any[]> = {
[K in keyof T]?: T[K] | R.Placeholder
};
type CleanedGaps<T extends any[]> = {
[K in keyof T]: NonNullable<T[K]>
};
type Gaps<T extends any[]> = CleanedGaps<PartialGaps<T>>;
type Curry<F extends ((...args: any) => any)> =
<T extends any[]>(...args: Tools.Cast<Tools.Cast<T, Gaps<Parameters<F>>>, any[]>) =>
GapsOf<T, Parameters<F>> extends [any, ...any[]]
? Curry<(...args: GapsOf<T, Parameters<F>> extends infer G ? Tools.Cast<G, any[]> : never) => ReturnType<F>>
: ReturnType<F>;
}

View File

@ -0,0 +1,4 @@
type M = { p: string };
type O = { m: () => M };
type X<T extends M> = T;
type FFG<T> = T extends O ? X<ReturnType<T['m']>> : never; // error!