mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-05-15 12:51:30 -05:00
Add isDeeplyNestedType logic to getResolvedBaseConstraint (#40971)
* Add isDeeplyNestedType logic to getResolvedBaseConstraint * Accept new baselines * Add regression test * Accept new baselines * Fix lint issue
This commit is contained in:
@@ -10913,9 +10913,12 @@ namespace ts {
|
||||
* circularly references the type variable.
|
||||
*/
|
||||
function getResolvedBaseConstraint(type: InstantiableType | UnionOrIntersectionType): Type {
|
||||
if (type.resolvedBaseConstraint) {
|
||||
return type.resolvedBaseConstraint;
|
||||
}
|
||||
let nonTerminating = false;
|
||||
return type.resolvedBaseConstraint ||
|
||||
(type.resolvedBaseConstraint = getTypeWithThisArgument(getImmediateBaseConstraint(type), type));
|
||||
const stack: Type[] = [];
|
||||
return type.resolvedBaseConstraint = getTypeWithThisArgument(getImmediateBaseConstraint(type), type);
|
||||
|
||||
function getImmediateBaseConstraint(t: Type): Type {
|
||||
if (!t.immediateBaseConstraint) {
|
||||
@@ -10932,9 +10935,14 @@ namespace ts {
|
||||
nonTerminating = true;
|
||||
return t.immediateBaseConstraint = noConstraintType;
|
||||
}
|
||||
constraintDepth++;
|
||||
let result = computeBaseConstraint(getSimplifiedType(t, /*writing*/ false));
|
||||
constraintDepth--;
|
||||
let result;
|
||||
if (!isDeeplyNestedType(t, stack, stack.length)) {
|
||||
stack.push(t);
|
||||
constraintDepth++;
|
||||
result = computeBaseConstraint(getSimplifiedType(t, /*writing*/ false));
|
||||
constraintDepth--;
|
||||
stack.pop();
|
||||
}
|
||||
if (!popTypeResolution()) {
|
||||
if (t.flags & TypeFlags.TypeParameter) {
|
||||
const errorNode = getConstraintDeclaration(<TypeParameter>t);
|
||||
|
||||
@@ -2,10 +2,9 @@ tests/cases/compiler/infiniteConstraints.ts(4,37): error TS2536: Type '"val"' ca
|
||||
tests/cases/compiler/infiniteConstraints.ts(31,43): error TS2322: Type 'Record<"val", "dup">' is not assignable to type 'never'.
|
||||
tests/cases/compiler/infiniteConstraints.ts(31,63): error TS2322: Type 'Record<"val", "dup">' is not assignable to type 'never'.
|
||||
tests/cases/compiler/infiniteConstraints.ts(36,71): error TS2536: Type '"foo"' cannot be used to index type 'T[keyof T]'.
|
||||
tests/cases/compiler/infiniteConstraints.ts(48,16): error TS2589: Type instantiation is excessively deep and possibly infinite.
|
||||
|
||||
|
||||
==== tests/cases/compiler/infiniteConstraints.ts (5 errors) ====
|
||||
==== tests/cases/compiler/infiniteConstraints.ts (4 errors) ====
|
||||
// Both of the following types trigger the recursion limiter in getImmediateBaseConstraint
|
||||
|
||||
type T1<B extends { [K in keyof B]: Extract<B[Exclude<keyof B, K>], { val: string }>["val"] }> = B;
|
||||
@@ -64,6 +63,4 @@ tests/cases/compiler/infiniteConstraints.ts(48,16): error TS2589: Type instantia
|
||||
|
||||
type Conv<T, U = T> =
|
||||
{ 0: [T]; 1: Prepend<T, Conv<ExactExtract<U, T>>>;}[U extends T ? 0 : 1];
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
!!! error TS2589: Type instantiation is excessively deep and possibly infinite.
|
||||
|
||||
@@ -21,7 +21,6 @@ tests/cases/compiler/recursiveConditionalTypes.ts(50,5): error TS2322: Type 'Tup
|
||||
Type 'number extends N ? number[] : _TupleOf<number, N, []>' is not assignable to type 'TupleOf<number, M>'.
|
||||
Type 'number[] | _TupleOf<number, N, []>' is not assignable to type 'TupleOf<number, M>'.
|
||||
Type 'number[]' is not assignable to type 'TupleOf<number, M>'.
|
||||
tests/cases/compiler/recursiveConditionalTypes.ts(116,5): error TS2589: Type instantiation is excessively deep and possibly infinite.
|
||||
tests/cases/compiler/recursiveConditionalTypes.ts(116,9): error TS2345: Argument of type 'Grow2<[], T>' is not assignable to parameter of type 'Grow1<[], T>'.
|
||||
Type '[] | Grow2<[string], T>' is not assignable to type 'Grow1<[], T>'.
|
||||
Type '[]' is not assignable to type 'Grow1<[], T>'.
|
||||
@@ -32,7 +31,7 @@ tests/cases/compiler/recursiveConditionalTypes.ts(116,9): error TS2345: Argument
|
||||
Type 'string' is not assignable to type 'number'.
|
||||
|
||||
|
||||
==== tests/cases/compiler/recursiveConditionalTypes.ts (10 errors) ====
|
||||
==== tests/cases/compiler/recursiveConditionalTypes.ts (9 errors) ====
|
||||
// Awaiting promises
|
||||
|
||||
type Awaited<T> =
|
||||
@@ -180,8 +179,6 @@ tests/cases/compiler/recursiveConditionalTypes.ts(116,9): error TS2345: Argument
|
||||
|
||||
function f21<T extends number>(x: Grow1<[], T>, y: Grow2<[], T>) {
|
||||
f21(y, x); // Error
|
||||
~~~~~~~~~
|
||||
!!! error TS2589: Type instantiation is excessively deep and possibly infinite.
|
||||
~
|
||||
!!! error TS2345: Argument of type 'Grow2<[], T>' is not assignable to parameter of type 'Grow1<[], T>'.
|
||||
!!! error TS2345: Type '[] | Grow2<[string], T>' is not assignable to type 'Grow1<[], T>'.
|
||||
|
||||
@@ -241,4 +241,26 @@ tests/cases/conformance/types/literal/templateLiteralTypes1.ts(205,16): error TS
|
||||
[true, true] extends [IsNegative<T>, IsNegative<Q>] ? 'Every thing is ok!' : ['strange', IsNegative<T>, IsNegative<Q>];
|
||||
|
||||
type BB = AA<-2, -2>;
|
||||
|
||||
// Repro from #40970
|
||||
|
||||
type PathKeys<T> =
|
||||
T extends readonly any[] ? Extract<keyof T, `${number}`> | SubKeys<T, Extract<keyof T, `${number}`>> :
|
||||
T extends object ? Extract<keyof T, string> | SubKeys<T, Extract<keyof T, string>> :
|
||||
never;
|
||||
|
||||
type SubKeys<T, K extends string> = K extends keyof T ? `${K}.${PathKeys<T[K]>}` : never;
|
||||
|
||||
declare function getProp2<T, P extends PathKeys<T>>(obj: T, path: P): PropType<T, P>;
|
||||
|
||||
const obj2 = {
|
||||
name: 'John',
|
||||
age: 42,
|
||||
cars: [
|
||||
{ make: 'Ford', age: 10 },
|
||||
{ make: 'Trabant', age: 35 }
|
||||
]
|
||||
} as const;
|
||||
|
||||
let make = getProp2(obj2, 'cars.1.make'); // 'Trabant'
|
||||
|
||||
@@ -213,6 +213,28 @@ type AA<T extends number, Q extends number> =
|
||||
[true, true] extends [IsNegative<T>, IsNegative<Q>] ? 'Every thing is ok!' : ['strange', IsNegative<T>, IsNegative<Q>];
|
||||
|
||||
type BB = AA<-2, -2>;
|
||||
|
||||
// Repro from #40970
|
||||
|
||||
type PathKeys<T> =
|
||||
T extends readonly any[] ? Extract<keyof T, `${number}`> | SubKeys<T, Extract<keyof T, `${number}`>> :
|
||||
T extends object ? Extract<keyof T, string> | SubKeys<T, Extract<keyof T, string>> :
|
||||
never;
|
||||
|
||||
type SubKeys<T, K extends string> = K extends keyof T ? `${K}.${PathKeys<T[K]>}` : never;
|
||||
|
||||
declare function getProp2<T, P extends PathKeys<T>>(obj: T, path: P): PropType<T, P>;
|
||||
|
||||
const obj2 = {
|
||||
name: 'John',
|
||||
age: 42,
|
||||
cars: [
|
||||
{ make: 'Ford', age: 10 },
|
||||
{ make: 'Trabant', age: 35 }
|
||||
]
|
||||
} as const;
|
||||
|
||||
let make = getProp2(obj2, 'cars.1.make'); // 'Trabant'
|
||||
|
||||
|
||||
//// [templateLiteralTypes1.js]
|
||||
@@ -243,6 +265,15 @@ getPropValue(obj, 'a.b'); // {c: number, d: string }
|
||||
getPropValue(obj, 'a.b.d'); // string
|
||||
getPropValue(obj, 'a.b.x'); // unknown
|
||||
getPropValue(obj, s); // unknown
|
||||
var obj2 = {
|
||||
name: 'John',
|
||||
age: 42,
|
||||
cars: [
|
||||
{ make: 'Ford', age: 10 },
|
||||
{ make: 'Trabant', age: 35 }
|
||||
]
|
||||
};
|
||||
var make = getProp2(obj2, 'cars.1.make'); // 'Trabant'
|
||||
|
||||
|
||||
//// [templateLiteralTypes1.d.ts]
|
||||
@@ -468,3 +499,18 @@ declare type AA<T extends number, Q extends number> = [
|
||||
true
|
||||
] extends [IsNegative<T>, IsNegative<Q>] ? 'Every thing is ok!' : ['strange', IsNegative<T>, IsNegative<Q>];
|
||||
declare type BB = AA<-2, -2>;
|
||||
declare type PathKeys<T> = T extends readonly any[] ? Extract<keyof T, `${number}`> | SubKeys<T, Extract<keyof T, `${number}`>> : T extends object ? Extract<keyof T, string> | SubKeys<T, Extract<keyof T, string>> : never;
|
||||
declare type SubKeys<T, K extends string> = K extends keyof T ? `${K}.${PathKeys<T[K]>}` : never;
|
||||
declare function getProp2<T, P extends PathKeys<T>>(obj: T, path: P): PropType<T, P>;
|
||||
declare const obj2: {
|
||||
readonly name: "John";
|
||||
readonly age: 42;
|
||||
readonly cars: readonly [{
|
||||
readonly make: "Ford";
|
||||
readonly age: 10;
|
||||
}, {
|
||||
readonly make: "Trabant";
|
||||
readonly age: 35;
|
||||
}];
|
||||
};
|
||||
declare let make: "Trabant";
|
||||
|
||||
@@ -869,3 +869,82 @@ type BB = AA<-2, -2>;
|
||||
>BB : Symbol(BB, Decl(templateLiteralTypes1.ts, 211, 123))
|
||||
>AA : Symbol(AA, Decl(templateLiteralTypes1.ts, 208, 79))
|
||||
|
||||
// Repro from #40970
|
||||
|
||||
type PathKeys<T> =
|
||||
>PathKeys : Symbol(PathKeys, Decl(templateLiteralTypes1.ts, 213, 21))
|
||||
>T : Symbol(T, Decl(templateLiteralTypes1.ts, 217, 14))
|
||||
|
||||
T extends readonly any[] ? Extract<keyof T, `${number}`> | SubKeys<T, Extract<keyof T, `${number}`>> :
|
||||
>T : Symbol(T, Decl(templateLiteralTypes1.ts, 217, 14))
|
||||
>Extract : Symbol(Extract, Decl(lib.es5.d.ts, --, --))
|
||||
>T : Symbol(T, Decl(templateLiteralTypes1.ts, 217, 14))
|
||||
>SubKeys : Symbol(SubKeys, Decl(templateLiteralTypes1.ts, 220, 10))
|
||||
>T : Symbol(T, Decl(templateLiteralTypes1.ts, 217, 14))
|
||||
>Extract : Symbol(Extract, Decl(lib.es5.d.ts, --, --))
|
||||
>T : Symbol(T, Decl(templateLiteralTypes1.ts, 217, 14))
|
||||
|
||||
T extends object ? Extract<keyof T, string> | SubKeys<T, Extract<keyof T, string>> :
|
||||
>T : Symbol(T, Decl(templateLiteralTypes1.ts, 217, 14))
|
||||
>Extract : Symbol(Extract, Decl(lib.es5.d.ts, --, --))
|
||||
>T : Symbol(T, Decl(templateLiteralTypes1.ts, 217, 14))
|
||||
>SubKeys : Symbol(SubKeys, Decl(templateLiteralTypes1.ts, 220, 10))
|
||||
>T : Symbol(T, Decl(templateLiteralTypes1.ts, 217, 14))
|
||||
>Extract : Symbol(Extract, Decl(lib.es5.d.ts, --, --))
|
||||
>T : Symbol(T, Decl(templateLiteralTypes1.ts, 217, 14))
|
||||
|
||||
never;
|
||||
|
||||
type SubKeys<T, K extends string> = K extends keyof T ? `${K}.${PathKeys<T[K]>}` : never;
|
||||
>SubKeys : Symbol(SubKeys, Decl(templateLiteralTypes1.ts, 220, 10))
|
||||
>T : Symbol(T, Decl(templateLiteralTypes1.ts, 222, 13))
|
||||
>K : Symbol(K, Decl(templateLiteralTypes1.ts, 222, 15))
|
||||
>K : Symbol(K, Decl(templateLiteralTypes1.ts, 222, 15))
|
||||
>T : Symbol(T, Decl(templateLiteralTypes1.ts, 222, 13))
|
||||
>K : Symbol(K, Decl(templateLiteralTypes1.ts, 222, 15))
|
||||
>PathKeys : Symbol(PathKeys, Decl(templateLiteralTypes1.ts, 213, 21))
|
||||
>T : Symbol(T, Decl(templateLiteralTypes1.ts, 222, 13))
|
||||
>K : Symbol(K, Decl(templateLiteralTypes1.ts, 222, 15))
|
||||
|
||||
declare function getProp2<T, P extends PathKeys<T>>(obj: T, path: P): PropType<T, P>;
|
||||
>getProp2 : Symbol(getProp2, Decl(templateLiteralTypes1.ts, 222, 89))
|
||||
>T : Symbol(T, Decl(templateLiteralTypes1.ts, 224, 26))
|
||||
>P : Symbol(P, Decl(templateLiteralTypes1.ts, 224, 28))
|
||||
>PathKeys : Symbol(PathKeys, Decl(templateLiteralTypes1.ts, 213, 21))
|
||||
>T : Symbol(T, Decl(templateLiteralTypes1.ts, 224, 26))
|
||||
>obj : Symbol(obj, Decl(templateLiteralTypes1.ts, 224, 52))
|
||||
>T : Symbol(T, Decl(templateLiteralTypes1.ts, 224, 26))
|
||||
>path : Symbol(path, Decl(templateLiteralTypes1.ts, 224, 59))
|
||||
>P : Symbol(P, Decl(templateLiteralTypes1.ts, 224, 28))
|
||||
>PropType : Symbol(PropType, Decl(templateLiteralTypes1.ts, 138, 69))
|
||||
>T : Symbol(T, Decl(templateLiteralTypes1.ts, 224, 26))
|
||||
>P : Symbol(P, Decl(templateLiteralTypes1.ts, 224, 28))
|
||||
|
||||
const obj2 = {
|
||||
>obj2 : Symbol(obj2, Decl(templateLiteralTypes1.ts, 226, 5))
|
||||
|
||||
name: 'John',
|
||||
>name : Symbol(name, Decl(templateLiteralTypes1.ts, 226, 14))
|
||||
|
||||
age: 42,
|
||||
>age : Symbol(age, Decl(templateLiteralTypes1.ts, 227, 17))
|
||||
|
||||
cars: [
|
||||
>cars : Symbol(cars, Decl(templateLiteralTypes1.ts, 228, 12))
|
||||
|
||||
{ make: 'Ford', age: 10 },
|
||||
>make : Symbol(make, Decl(templateLiteralTypes1.ts, 230, 9))
|
||||
>age : Symbol(age, Decl(templateLiteralTypes1.ts, 230, 23))
|
||||
|
||||
{ make: 'Trabant', age: 35 }
|
||||
>make : Symbol(make, Decl(templateLiteralTypes1.ts, 231, 9))
|
||||
>age : Symbol(age, Decl(templateLiteralTypes1.ts, 231, 26))
|
||||
|
||||
]
|
||||
} as const;
|
||||
|
||||
let make = getProp2(obj2, 'cars.1.make'); // 'Trabant'
|
||||
>make : Symbol(make, Decl(templateLiteralTypes1.ts, 235, 3))
|
||||
>getProp2 : Symbol(getProp2, Decl(templateLiteralTypes1.ts, 222, 89))
|
||||
>obj2 : Symbol(obj2, Decl(templateLiteralTypes1.ts, 226, 5))
|
||||
|
||||
|
||||
@@ -536,3 +536,61 @@ type BB = AA<-2, -2>;
|
||||
>-2 : -2
|
||||
>2 : 2
|
||||
|
||||
// Repro from #40970
|
||||
|
||||
type PathKeys<T> =
|
||||
>PathKeys : PathKeys<T>
|
||||
|
||||
T extends readonly any[] ? Extract<keyof T, `${number}`> | SubKeys<T, Extract<keyof T, `${number}`>> :
|
||||
T extends object ? Extract<keyof T, string> | SubKeys<T, Extract<keyof T, string>> :
|
||||
never;
|
||||
|
||||
type SubKeys<T, K extends string> = K extends keyof T ? `${K}.${PathKeys<T[K]>}` : never;
|
||||
>SubKeys : SubKeys<T, K>
|
||||
|
||||
declare function getProp2<T, P extends PathKeys<T>>(obj: T, path: P): PropType<T, P>;
|
||||
>getProp2 : <T, P extends PathKeys<T>>(obj: T, path: P) => PropType<T, P>
|
||||
>obj : T
|
||||
>path : P
|
||||
|
||||
const obj2 = {
|
||||
>obj2 : { readonly name: "John"; readonly age: 42; readonly cars: readonly [{ readonly make: "Ford"; readonly age: 10; }, { readonly make: "Trabant"; readonly age: 35; }]; }
|
||||
>{ name: 'John', age: 42, cars: [ { make: 'Ford', age: 10 }, { make: 'Trabant', age: 35 } ]} as const : { readonly name: "John"; readonly age: 42; readonly cars: readonly [{ readonly make: "Ford"; readonly age: 10; }, { readonly make: "Trabant"; readonly age: 35; }]; }
|
||||
>{ name: 'John', age: 42, cars: [ { make: 'Ford', age: 10 }, { make: 'Trabant', age: 35 } ]} : { readonly name: "John"; readonly age: 42; readonly cars: readonly [{ readonly make: "Ford"; readonly age: 10; }, { readonly make: "Trabant"; readonly age: 35; }]; }
|
||||
|
||||
name: 'John',
|
||||
>name : "John"
|
||||
>'John' : "John"
|
||||
|
||||
age: 42,
|
||||
>age : 42
|
||||
>42 : 42
|
||||
|
||||
cars: [
|
||||
>cars : readonly [{ readonly make: "Ford"; readonly age: 10; }, { readonly make: "Trabant"; readonly age: 35; }]
|
||||
>[ { make: 'Ford', age: 10 }, { make: 'Trabant', age: 35 } ] : readonly [{ readonly make: "Ford"; readonly age: 10; }, { readonly make: "Trabant"; readonly age: 35; }]
|
||||
|
||||
{ make: 'Ford', age: 10 },
|
||||
>{ make: 'Ford', age: 10 } : { readonly make: "Ford"; readonly age: 10; }
|
||||
>make : "Ford"
|
||||
>'Ford' : "Ford"
|
||||
>age : 10
|
||||
>10 : 10
|
||||
|
||||
{ make: 'Trabant', age: 35 }
|
||||
>{ make: 'Trabant', age: 35 } : { readonly make: "Trabant"; readonly age: 35; }
|
||||
>make : "Trabant"
|
||||
>'Trabant' : "Trabant"
|
||||
>age : 35
|
||||
>35 : 35
|
||||
|
||||
]
|
||||
} as const;
|
||||
|
||||
let make = getProp2(obj2, 'cars.1.make'); // 'Trabant'
|
||||
>make : "Trabant"
|
||||
>getProp2(obj2, 'cars.1.make') : "Trabant"
|
||||
>getProp2 : <T, P extends PathKeys<T>>(obj: T, path: P) => PropType<T, P>
|
||||
>obj2 : { readonly name: "John"; readonly age: 42; readonly cars: readonly [{ readonly make: "Ford"; readonly age: 10; }, { readonly make: "Trabant"; readonly age: 35; }]; }
|
||||
>'cars.1.make' : "cars.1.make"
|
||||
|
||||
|
||||
@@ -215,3 +215,25 @@ type AA<T extends number, Q extends number> =
|
||||
[true, true] extends [IsNegative<T>, IsNegative<Q>] ? 'Every thing is ok!' : ['strange', IsNegative<T>, IsNegative<Q>];
|
||||
|
||||
type BB = AA<-2, -2>;
|
||||
|
||||
// Repro from #40970
|
||||
|
||||
type PathKeys<T> =
|
||||
T extends readonly any[] ? Extract<keyof T, `${number}`> | SubKeys<T, Extract<keyof T, `${number}`>> :
|
||||
T extends object ? Extract<keyof T, string> | SubKeys<T, Extract<keyof T, string>> :
|
||||
never;
|
||||
|
||||
type SubKeys<T, K extends string> = K extends keyof T ? `${K}.${PathKeys<T[K]>}` : never;
|
||||
|
||||
declare function getProp2<T, P extends PathKeys<T>>(obj: T, path: P): PropType<T, P>;
|
||||
|
||||
const obj2 = {
|
||||
name: 'John',
|
||||
age: 42,
|
||||
cars: [
|
||||
{ make: 'Ford', age: 10 },
|
||||
{ make: 'Trabant', age: 35 }
|
||||
]
|
||||
} as const;
|
||||
|
||||
let make = getProp2(obj2, 'cars.1.make'); // 'Trabant'
|
||||
|
||||
Reference in New Issue
Block a user