mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-27 23:58:38 -06:00
Preserve substitution types in check position of conditional types (#41841)
* Preserve substitution types in check types of conditional types * Undo changes from #32093 * Add regression tests * Accept new baselines
This commit is contained in:
parent
0fa41db6c6
commit
646f5b3c4e
@ -14089,13 +14089,6 @@ 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.
|
||||
@ -14107,7 +14100,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 = unwrapSubstitution(getSimplifiedType(type.objectType, writing));
|
||||
const objectType = 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)
|
||||
@ -14325,11 +14318,7 @@ namespace ts {
|
||||
let combinedMapper: TypeMapper | undefined;
|
||||
if (root.inferTypeParameters) {
|
||||
const context = createInferenceContext(root.inferTypeParameters, /*signature*/ undefined, InferenceFlags.None);
|
||||
// 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)) {
|
||||
if (!checkTypeInstantiable) {
|
||||
// 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.
|
||||
@ -14374,10 +14363,9 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
// Return a deferred type for a check that is neither definitely true nor definitely false
|
||||
const erasedCheckType = getActualTypeVariable(checkType);
|
||||
result = <ConditionalType>createType(TypeFlags.Conditional);
|
||||
result.root = root;
|
||||
result.checkType = erasedCheckType;
|
||||
result.checkType = checkType;
|
||||
result.extendsType = extendsType;
|
||||
result.mapper = mapper;
|
||||
result.combinedMapper = combinedMapper;
|
||||
@ -20210,12 +20198,6 @@ 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) {
|
||||
|
||||
@ -189,4 +189,24 @@ tests/cases/compiler/recursiveConditionalTypes.ts(116,9): error TS2345: Argument
|
||||
!!! error TS2345: Type '[string]' is not assignable to type '[number]'.
|
||||
!!! error TS2345: Type 'string' is not assignable to type 'number'.
|
||||
}
|
||||
|
||||
// Repros from #41756
|
||||
|
||||
type ParseSuccess<R extends string> = { rest: R };
|
||||
|
||||
type ParseManyWhitespace<S extends string> =
|
||||
S extends ` ${infer R0}` ?
|
||||
ParseManyWhitespace<R0> extends ParseSuccess<infer R1> ? ParseSuccess<R1> : null :
|
||||
ParseSuccess<S>;
|
||||
|
||||
type TP1 = ParseManyWhitespace<" foo">;
|
||||
|
||||
type ParseManyWhitespace2<S extends string> =
|
||||
S extends ` ${infer R0}` ?
|
||||
Helper<ParseManyWhitespace2<R0>> :
|
||||
ParseSuccess<S>;
|
||||
|
||||
type Helper<T> = T extends ParseSuccess<infer R> ? ParseSuccess<R> : null
|
||||
|
||||
type TP2 = ParseManyWhitespace2<" foo">;
|
||||
|
||||
@ -116,6 +116,26 @@ type Grow2<T extends unknown[], N extends number> = T['length'] extends N ? T :
|
||||
function f21<T extends number>(x: Grow1<[], T>, y: Grow2<[], T>) {
|
||||
f21(y, x); // Error
|
||||
}
|
||||
|
||||
// Repros from #41756
|
||||
|
||||
type ParseSuccess<R extends string> = { rest: R };
|
||||
|
||||
type ParseManyWhitespace<S extends string> =
|
||||
S extends ` ${infer R0}` ?
|
||||
ParseManyWhitespace<R0> extends ParseSuccess<infer R1> ? ParseSuccess<R1> : null :
|
||||
ParseSuccess<S>;
|
||||
|
||||
type TP1 = ParseManyWhitespace<" foo">;
|
||||
|
||||
type ParseManyWhitespace2<S extends string> =
|
||||
S extends ` ${infer R0}` ?
|
||||
Helper<ParseManyWhitespace2<R0>> :
|
||||
ParseSuccess<S>;
|
||||
|
||||
type Helper<T> = T extends ParseSuccess<infer R> ? ParseSuccess<R> : null
|
||||
|
||||
type TP2 = ParseManyWhitespace2<" foo">;
|
||||
|
||||
|
||||
//// [recursiveConditionalTypes.js]
|
||||
@ -214,3 +234,11 @@ declare function f20<T, U extends T>(x: Unpack1<T>, y: Unpack2<T>): void;
|
||||
declare type Grow1<T extends unknown[], N extends number> = T['length'] extends N ? T : Grow1<[number, ...T], N>;
|
||||
declare type Grow2<T extends unknown[], N extends number> = T['length'] extends N ? T : Grow2<[string, ...T], N>;
|
||||
declare function f21<T extends number>(x: Grow1<[], T>, y: Grow2<[], T>): void;
|
||||
declare type ParseSuccess<R extends string> = {
|
||||
rest: R;
|
||||
};
|
||||
declare type ParseManyWhitespace<S extends string> = S extends ` ${infer R0}` ? ParseManyWhitespace<R0> extends ParseSuccess<infer R1> ? ParseSuccess<R1> : null : ParseSuccess<S>;
|
||||
declare type TP1 = ParseManyWhitespace<" foo">;
|
||||
declare type ParseManyWhitespace2<S extends string> = S extends ` ${infer R0}` ? Helper<ParseManyWhitespace2<R0>> : ParseSuccess<S>;
|
||||
declare type Helper<T> = T extends ParseSuccess<infer R> ? ParseSuccess<R> : null;
|
||||
declare type TP2 = ParseManyWhitespace2<" foo">;
|
||||
|
||||
@ -465,3 +465,65 @@ function f21<T extends number>(x: Grow1<[], T>, y: Grow2<[], T>) {
|
||||
>x : Symbol(x, Decl(recursiveConditionalTypes.ts, 114, 31))
|
||||
}
|
||||
|
||||
// Repros from #41756
|
||||
|
||||
type ParseSuccess<R extends string> = { rest: R };
|
||||
>ParseSuccess : Symbol(ParseSuccess, Decl(recursiveConditionalTypes.ts, 116, 1))
|
||||
>R : Symbol(R, Decl(recursiveConditionalTypes.ts, 120, 18))
|
||||
>rest : Symbol(rest, Decl(recursiveConditionalTypes.ts, 120, 39))
|
||||
>R : Symbol(R, Decl(recursiveConditionalTypes.ts, 120, 18))
|
||||
|
||||
type ParseManyWhitespace<S extends string> =
|
||||
>ParseManyWhitespace : Symbol(ParseManyWhitespace, Decl(recursiveConditionalTypes.ts, 120, 50))
|
||||
>S : Symbol(S, Decl(recursiveConditionalTypes.ts, 122, 25))
|
||||
|
||||
S extends ` ${infer R0}` ?
|
||||
>S : Symbol(S, Decl(recursiveConditionalTypes.ts, 122, 25))
|
||||
>R0 : Symbol(R0, Decl(recursiveConditionalTypes.ts, 123, 23))
|
||||
|
||||
ParseManyWhitespace<R0> extends ParseSuccess<infer R1> ? ParseSuccess<R1> : null :
|
||||
>ParseManyWhitespace : Symbol(ParseManyWhitespace, Decl(recursiveConditionalTypes.ts, 120, 50))
|
||||
>R0 : Symbol(R0, Decl(recursiveConditionalTypes.ts, 123, 23))
|
||||
>ParseSuccess : Symbol(ParseSuccess, Decl(recursiveConditionalTypes.ts, 116, 1))
|
||||
>R1 : Symbol(R1, Decl(recursiveConditionalTypes.ts, 124, 58))
|
||||
>ParseSuccess : Symbol(ParseSuccess, Decl(recursiveConditionalTypes.ts, 116, 1))
|
||||
>R1 : Symbol(R1, Decl(recursiveConditionalTypes.ts, 124, 58))
|
||||
|
||||
ParseSuccess<S>;
|
||||
>ParseSuccess : Symbol(ParseSuccess, Decl(recursiveConditionalTypes.ts, 116, 1))
|
||||
>S : Symbol(S, Decl(recursiveConditionalTypes.ts, 122, 25))
|
||||
|
||||
type TP1 = ParseManyWhitespace<" foo">;
|
||||
>TP1 : Symbol(TP1, Decl(recursiveConditionalTypes.ts, 125, 24))
|
||||
>ParseManyWhitespace : Symbol(ParseManyWhitespace, Decl(recursiveConditionalTypes.ts, 120, 50))
|
||||
|
||||
type ParseManyWhitespace2<S extends string> =
|
||||
>ParseManyWhitespace2 : Symbol(ParseManyWhitespace2, Decl(recursiveConditionalTypes.ts, 127, 39))
|
||||
>S : Symbol(S, Decl(recursiveConditionalTypes.ts, 129, 26))
|
||||
|
||||
S extends ` ${infer R0}` ?
|
||||
>S : Symbol(S, Decl(recursiveConditionalTypes.ts, 129, 26))
|
||||
>R0 : Symbol(R0, Decl(recursiveConditionalTypes.ts, 130, 23))
|
||||
|
||||
Helper<ParseManyWhitespace2<R0>> :
|
||||
>Helper : Symbol(Helper, Decl(recursiveConditionalTypes.ts, 132, 24))
|
||||
>ParseManyWhitespace2 : Symbol(ParseManyWhitespace2, Decl(recursiveConditionalTypes.ts, 127, 39))
|
||||
>R0 : Symbol(R0, Decl(recursiveConditionalTypes.ts, 130, 23))
|
||||
|
||||
ParseSuccess<S>;
|
||||
>ParseSuccess : Symbol(ParseSuccess, Decl(recursiveConditionalTypes.ts, 116, 1))
|
||||
>S : Symbol(S, Decl(recursiveConditionalTypes.ts, 129, 26))
|
||||
|
||||
type Helper<T> = T extends ParseSuccess<infer R> ? ParseSuccess<R> : null
|
||||
>Helper : Symbol(Helper, Decl(recursiveConditionalTypes.ts, 132, 24))
|
||||
>T : Symbol(T, Decl(recursiveConditionalTypes.ts, 134, 12))
|
||||
>T : Symbol(T, Decl(recursiveConditionalTypes.ts, 134, 12))
|
||||
>ParseSuccess : Symbol(ParseSuccess, Decl(recursiveConditionalTypes.ts, 116, 1))
|
||||
>R : Symbol(R, Decl(recursiveConditionalTypes.ts, 134, 45))
|
||||
>ParseSuccess : Symbol(ParseSuccess, Decl(recursiveConditionalTypes.ts, 116, 1))
|
||||
>R : Symbol(R, Decl(recursiveConditionalTypes.ts, 134, 45))
|
||||
|
||||
type TP2 = ParseManyWhitespace2<" foo">;
|
||||
>TP2 : Symbol(TP2, Decl(recursiveConditionalTypes.ts, 134, 73))
|
||||
>ParseManyWhitespace2 : Symbol(ParseManyWhitespace2, Decl(recursiveConditionalTypes.ts, 127, 39))
|
||||
|
||||
|
||||
@ -310,3 +310,35 @@ function f21<T extends number>(x: Grow1<[], T>, y: Grow2<[], T>) {
|
||||
>x : Grow1<[], T>
|
||||
}
|
||||
|
||||
// Repros from #41756
|
||||
|
||||
type ParseSuccess<R extends string> = { rest: R };
|
||||
>ParseSuccess : ParseSuccess<R>
|
||||
>rest : R
|
||||
|
||||
type ParseManyWhitespace<S extends string> =
|
||||
>ParseManyWhitespace : ParseManyWhitespace<S>
|
||||
|
||||
S extends ` ${infer R0}` ?
|
||||
ParseManyWhitespace<R0> extends ParseSuccess<infer R1> ? ParseSuccess<R1> : null :
|
||||
>null : null
|
||||
|
||||
ParseSuccess<S>;
|
||||
|
||||
type TP1 = ParseManyWhitespace<" foo">;
|
||||
>TP1 : ParseSuccess<"foo">
|
||||
|
||||
type ParseManyWhitespace2<S extends string> =
|
||||
>ParseManyWhitespace2 : ParseManyWhitespace2<S>
|
||||
|
||||
S extends ` ${infer R0}` ?
|
||||
Helper<ParseManyWhitespace2<R0>> :
|
||||
ParseSuccess<S>;
|
||||
|
||||
type Helper<T> = T extends ParseSuccess<infer R> ? ParseSuccess<R> : null
|
||||
>Helper : Helper<T>
|
||||
>null : null
|
||||
|
||||
type TP2 = ParseManyWhitespace2<" foo">;
|
||||
>TP2 : ParseSuccess<"foo">
|
||||
|
||||
|
||||
@ -119,3 +119,23 @@ type Grow2<T extends unknown[], N extends number> = T['length'] extends N ? T :
|
||||
function f21<T extends number>(x: Grow1<[], T>, y: Grow2<[], T>) {
|
||||
f21(y, x); // Error
|
||||
}
|
||||
|
||||
// Repros from #41756
|
||||
|
||||
type ParseSuccess<R extends string> = { rest: R };
|
||||
|
||||
type ParseManyWhitespace<S extends string> =
|
||||
S extends ` ${infer R0}` ?
|
||||
ParseManyWhitespace<R0> extends ParseSuccess<infer R1> ? ParseSuccess<R1> : null :
|
||||
ParseSuccess<S>;
|
||||
|
||||
type TP1 = ParseManyWhitespace<" foo">;
|
||||
|
||||
type ParseManyWhitespace2<S extends string> =
|
||||
S extends ` ${infer R0}` ?
|
||||
Helper<ParseManyWhitespace2<R0>> :
|
||||
ParseSuccess<S>;
|
||||
|
||||
type Helper<T> = T extends ParseSuccess<infer R> ? ParseSuccess<R> : null
|
||||
|
||||
type TP2 = ParseManyWhitespace2<" foo">;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user