diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 79d6a2fbcdd..0a2d154b449 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -23682,10 +23682,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return false; } - function isTypeParameterAtTopLevel(type: Type, typeParameter: TypeParameter): boolean { - return !!(type === typeParameter || - type.flags & TypeFlags.UnionOrIntersection && some((type as UnionOrIntersectionType).types, t => isTypeParameterAtTopLevel(t, typeParameter)) || - type.flags & TypeFlags.Conditional && (getTrueTypeFromConditionalType(type as ConditionalType) === typeParameter || getFalseTypeFromConditionalType(type as ConditionalType) === typeParameter)); + function isTypeParameterAtTopLevel(type: Type, tp: TypeParameter, depth = 0): boolean { + return !!(type === tp || + type.flags & TypeFlags.UnionOrIntersection && some((type as UnionOrIntersectionType).types, t => isTypeParameterAtTopLevel(t, tp, depth)) || + depth < 3 && type.flags & TypeFlags.Conditional && ( + isTypeParameterAtTopLevel(getTrueTypeFromConditionalType(type as ConditionalType), tp, depth + 1) || + isTypeParameterAtTopLevel(getFalseTypeFromConditionalType(type as ConditionalType), tp, depth + 1))); } function isTypeParameterAtTopLevelInReturnType(signature: Signature, typeParameter: TypeParameter) { diff --git a/tests/baselines/reference/wideningWithTopLevelTypeParameter.symbols b/tests/baselines/reference/wideningWithTopLevelTypeParameter.symbols new file mode 100644 index 00000000000..7eb9498cf21 --- /dev/null +++ b/tests/baselines/reference/wideningWithTopLevelTypeParameter.symbols @@ -0,0 +1,133 @@ +=== tests/cases/compiler/wideningWithTopLevelTypeParameter.ts === +type C1 = T extends unknown ? T | undefined : never; +>C1 : Symbol(C1, Decl(wideningWithTopLevelTypeParameter.ts, 0, 0)) +>T : Symbol(T, Decl(wideningWithTopLevelTypeParameter.ts, 0, 8)) +>T : Symbol(T, Decl(wideningWithTopLevelTypeParameter.ts, 0, 8)) +>T : Symbol(T, Decl(wideningWithTopLevelTypeParameter.ts, 0, 8)) + +type C2 = T extends unknown ? T | undefined : never; +>C2 : Symbol(C2, Decl(wideningWithTopLevelTypeParameter.ts, 0, 55)) +>T : Symbol(T, Decl(wideningWithTopLevelTypeParameter.ts, 1, 8)) +>T : Symbol(T, Decl(wideningWithTopLevelTypeParameter.ts, 1, 8)) +>T : Symbol(T, Decl(wideningWithTopLevelTypeParameter.ts, 1, 8)) + +type C3 = T extends unknown ? T | undefined : never; +>C3 : Symbol(C3, Decl(wideningWithTopLevelTypeParameter.ts, 1, 55)) +>T : Symbol(T, Decl(wideningWithTopLevelTypeParameter.ts, 2, 8)) +>T : Symbol(T, Decl(wideningWithTopLevelTypeParameter.ts, 2, 8)) +>T : Symbol(T, Decl(wideningWithTopLevelTypeParameter.ts, 2, 8)) + +type C4 = T extends unknown ? T | undefined : never; +>C4 : Symbol(C4, Decl(wideningWithTopLevelTypeParameter.ts, 2, 55)) +>T : Symbol(T, Decl(wideningWithTopLevelTypeParameter.ts, 3, 8)) +>T : Symbol(T, Decl(wideningWithTopLevelTypeParameter.ts, 3, 8)) +>T : Symbol(T, Decl(wideningWithTopLevelTypeParameter.ts, 3, 8)) + +declare function f0(x: T): [T]; +>f0 : Symbol(f0, Decl(wideningWithTopLevelTypeParameter.ts, 3, 55)) +>T : Symbol(T, Decl(wideningWithTopLevelTypeParameter.ts, 5, 20)) +>x : Symbol(x, Decl(wideningWithTopLevelTypeParameter.ts, 5, 23)) +>T : Symbol(T, Decl(wideningWithTopLevelTypeParameter.ts, 5, 20)) +>T : Symbol(T, Decl(wideningWithTopLevelTypeParameter.ts, 5, 20)) + +declare function f1(x: C1): [T]; +>f1 : Symbol(f1, Decl(wideningWithTopLevelTypeParameter.ts, 5, 34)) +>T : Symbol(T, Decl(wideningWithTopLevelTypeParameter.ts, 6, 20)) +>x : Symbol(x, Decl(wideningWithTopLevelTypeParameter.ts, 6, 23)) +>C1 : Symbol(C1, Decl(wideningWithTopLevelTypeParameter.ts, 0, 0)) +>T : Symbol(T, Decl(wideningWithTopLevelTypeParameter.ts, 6, 20)) +>T : Symbol(T, Decl(wideningWithTopLevelTypeParameter.ts, 6, 20)) + +declare function f2(x: C1>): [T]; +>f2 : Symbol(f2, Decl(wideningWithTopLevelTypeParameter.ts, 6, 38)) +>T : Symbol(T, Decl(wideningWithTopLevelTypeParameter.ts, 7, 20)) +>x : Symbol(x, Decl(wideningWithTopLevelTypeParameter.ts, 7, 23)) +>C1 : Symbol(C1, Decl(wideningWithTopLevelTypeParameter.ts, 0, 0)) +>C2 : Symbol(C2, Decl(wideningWithTopLevelTypeParameter.ts, 0, 55)) +>T : Symbol(T, Decl(wideningWithTopLevelTypeParameter.ts, 7, 20)) +>T : Symbol(T, Decl(wideningWithTopLevelTypeParameter.ts, 7, 20)) + +declare function f3(x: C1>>): [T]; +>f3 : Symbol(f3, Decl(wideningWithTopLevelTypeParameter.ts, 7, 42)) +>T : Symbol(T, Decl(wideningWithTopLevelTypeParameter.ts, 8, 20)) +>x : Symbol(x, Decl(wideningWithTopLevelTypeParameter.ts, 8, 23)) +>C1 : Symbol(C1, Decl(wideningWithTopLevelTypeParameter.ts, 0, 0)) +>C2 : Symbol(C2, Decl(wideningWithTopLevelTypeParameter.ts, 0, 55)) +>C3 : Symbol(C3, Decl(wideningWithTopLevelTypeParameter.ts, 1, 55)) +>T : Symbol(T, Decl(wideningWithTopLevelTypeParameter.ts, 8, 20)) +>T : Symbol(T, Decl(wideningWithTopLevelTypeParameter.ts, 8, 20)) + +declare function f4(x: C1>>>): [T]; +>f4 : Symbol(f4, Decl(wideningWithTopLevelTypeParameter.ts, 8, 46)) +>T : Symbol(T, Decl(wideningWithTopLevelTypeParameter.ts, 9, 20)) +>x : Symbol(x, Decl(wideningWithTopLevelTypeParameter.ts, 9, 23)) +>C1 : Symbol(C1, Decl(wideningWithTopLevelTypeParameter.ts, 0, 0)) +>C2 : Symbol(C2, Decl(wideningWithTopLevelTypeParameter.ts, 0, 55)) +>C3 : Symbol(C3, Decl(wideningWithTopLevelTypeParameter.ts, 1, 55)) +>C4 : Symbol(C4, Decl(wideningWithTopLevelTypeParameter.ts, 2, 55)) +>T : Symbol(T, Decl(wideningWithTopLevelTypeParameter.ts, 9, 20)) +>T : Symbol(T, Decl(wideningWithTopLevelTypeParameter.ts, 9, 20)) + +const c0 = f0(7); // [number] +>c0 : Symbol(c0, Decl(wideningWithTopLevelTypeParameter.ts, 11, 5)) +>f0 : Symbol(f0, Decl(wideningWithTopLevelTypeParameter.ts, 3, 55)) + +const c1 = f1(7); // [number] +>c1 : Symbol(c1, Decl(wideningWithTopLevelTypeParameter.ts, 12, 5)) +>f1 : Symbol(f1, Decl(wideningWithTopLevelTypeParameter.ts, 5, 34)) + +const c2 = f2(7); // [number] +>c2 : Symbol(c2, Decl(wideningWithTopLevelTypeParameter.ts, 13, 5)) +>f2 : Symbol(f2, Decl(wideningWithTopLevelTypeParameter.ts, 6, 38)) + +const c3 = f3(7); // [number] +>c3 : Symbol(c3, Decl(wideningWithTopLevelTypeParameter.ts, 14, 5)) +>f3 : Symbol(f3, Decl(wideningWithTopLevelTypeParameter.ts, 7, 42)) + +const c4 = f4(7); // [7] since we have an internal nesting limit of 3 +>c4 : Symbol(c4, Decl(wideningWithTopLevelTypeParameter.ts, 15, 5)) +>f4 : Symbol(f4, Decl(wideningWithTopLevelTypeParameter.ts, 8, 46)) + +// Repro from #52620 + +class FormControl { +>FormControl : Symbol(FormControl, Decl(wideningWithTopLevelTypeParameter.ts, 15, 17)) +>T : Symbol(T, Decl(wideningWithTopLevelTypeParameter.ts, 19, 18)) + + constructor(t: T extends undefined ? never : T) {} +>t : Symbol(t, Decl(wideningWithTopLevelTypeParameter.ts, 20, 16)) +>T : Symbol(T, Decl(wideningWithTopLevelTypeParameter.ts, 19, 18)) +>T : Symbol(T, Decl(wideningWithTopLevelTypeParameter.ts, 19, 18)) +} + +const a = new FormControl(''); // string +>a : Symbol(a, Decl(wideningWithTopLevelTypeParameter.ts, 23, 5)) +>FormControl : Symbol(FormControl, Decl(wideningWithTopLevelTypeParameter.ts, 15, 17)) + +class FormControl2 { +>FormControl2 : Symbol(FormControl2, Decl(wideningWithTopLevelTypeParameter.ts, 23, 30)) +>T : Symbol(T, Decl(wideningWithTopLevelTypeParameter.ts, 25, 19)) + + constructor(t: T | string) {} +>t : Symbol(t, Decl(wideningWithTopLevelTypeParameter.ts, 26, 16)) +>T : Symbol(T, Decl(wideningWithTopLevelTypeParameter.ts, 25, 19)) +} + +const b = new FormControl2(''); // string +>b : Symbol(b, Decl(wideningWithTopLevelTypeParameter.ts, 29, 5)) +>FormControl2 : Symbol(FormControl2, Decl(wideningWithTopLevelTypeParameter.ts, 23, 30)) + +class FormControl3 { +>FormControl3 : Symbol(FormControl3, Decl(wideningWithTopLevelTypeParameter.ts, 29, 31)) +>T : Symbol(T, Decl(wideningWithTopLevelTypeParameter.ts, 31, 19)) + + constructor(t: T extends undefined ? never : T | string) {} +>t : Symbol(t, Decl(wideningWithTopLevelTypeParameter.ts, 32, 16)) +>T : Symbol(T, Decl(wideningWithTopLevelTypeParameter.ts, 31, 19)) +>T : Symbol(T, Decl(wideningWithTopLevelTypeParameter.ts, 31, 19)) +} + +const c = new FormControl3(''); // string +>c : Symbol(c, Decl(wideningWithTopLevelTypeParameter.ts, 35, 5)) +>FormControl3 : Symbol(FormControl3, Decl(wideningWithTopLevelTypeParameter.ts, 29, 31)) + diff --git a/tests/baselines/reference/wideningWithTopLevelTypeParameter.types b/tests/baselines/reference/wideningWithTopLevelTypeParameter.types new file mode 100644 index 00000000000..c29e4a80e20 --- /dev/null +++ b/tests/baselines/reference/wideningWithTopLevelTypeParameter.types @@ -0,0 +1,104 @@ +=== tests/cases/compiler/wideningWithTopLevelTypeParameter.ts === +type C1 = T extends unknown ? T | undefined : never; +>C1 : C1 + +type C2 = T extends unknown ? T | undefined : never; +>C2 : C2 + +type C3 = T extends unknown ? T | undefined : never; +>C3 : C3 + +type C4 = T extends unknown ? T | undefined : never; +>C4 : C4 + +declare function f0(x: T): [T]; +>f0 : (x: T) => [T] +>x : T + +declare function f1(x: C1): [T]; +>f1 : (x: C1) => [T] +>x : C1 + +declare function f2(x: C1>): [T]; +>f2 : (x: C1>) => [T] +>x : C1> + +declare function f3(x: C1>>): [T]; +>f3 : (x: C1>>) => [T] +>x : C1>> + +declare function f4(x: C1>>>): [T]; +>f4 : (x: C1>>>) => [T] +>x : C1>>> + +const c0 = f0(7); // [number] +>c0 : [number] +>f0(7) : [number] +>f0 : (x: T) => [T] +>7 : 7 + +const c1 = f1(7); // [number] +>c1 : [number] +>f1(7) : [number] +>f1 : (x: C1) => [T] +>7 : 7 + +const c2 = f2(7); // [number] +>c2 : [number] +>f2(7) : [number] +>f2 : (x: C1>) => [T] +>7 : 7 + +const c3 = f3(7); // [number] +>c3 : [number] +>f3(7) : [number] +>f3 : (x: C1>>) => [T] +>7 : 7 + +const c4 = f4(7); // [7] since we have an internal nesting limit of 3 +>c4 : [7] +>f4(7) : [7] +>f4 : (x: C1>>>) => [T] +>7 : 7 + +// Repro from #52620 + +class FormControl { +>FormControl : FormControl + + constructor(t: T extends undefined ? never : T) {} +>t : T extends undefined ? never : T +} + +const a = new FormControl(''); // string +>a : FormControl +>new FormControl('') : FormControl +>FormControl : typeof FormControl +>'' : "" + +class FormControl2 { +>FormControl2 : FormControl2 + + constructor(t: T | string) {} +>t : string | T +} + +const b = new FormControl2(''); // string +>b : FormControl2 +>new FormControl2('') : FormControl2 +>FormControl2 : typeof FormControl2 +>'' : "" + +class FormControl3 { +>FormControl3 : FormControl3 + + constructor(t: T extends undefined ? never : T | string) {} +>t : T extends undefined ? never : string | T +} + +const c = new FormControl3(''); // string +>c : FormControl3 +>new FormControl3('') : FormControl3 +>FormControl3 : typeof FormControl3 +>'' : "" + diff --git a/tests/cases/compiler/wideningWithTopLevelTypeParameter.ts b/tests/cases/compiler/wideningWithTopLevelTypeParameter.ts new file mode 100644 index 00000000000..061fab5d4ed --- /dev/null +++ b/tests/cases/compiler/wideningWithTopLevelTypeParameter.ts @@ -0,0 +1,39 @@ +// @strict: true +// @noEmit: true + +type C1 = T extends unknown ? T | undefined : never; +type C2 = T extends unknown ? T | undefined : never; +type C3 = T extends unknown ? T | undefined : never; +type C4 = T extends unknown ? T | undefined : never; + +declare function f0(x: T): [T]; +declare function f1(x: C1): [T]; +declare function f2(x: C1>): [T]; +declare function f3(x: C1>>): [T]; +declare function f4(x: C1>>>): [T]; + +const c0 = f0(7); // [number] +const c1 = f1(7); // [number] +const c2 = f2(7); // [number] +const c3 = f3(7); // [number] +const c4 = f4(7); // [7] since we have an internal nesting limit of 3 + +// Repro from #52620 + +class FormControl { + constructor(t: T extends undefined ? never : T) {} +} + +const a = new FormControl(''); // string + +class FormControl2 { + constructor(t: T | string) {} +} + +const b = new FormControl2(''); // string + +class FormControl3 { + constructor(t: T extends undefined ? never : T | string) {} +} + +const c = new FormControl3(''); // string