diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index d825b0d971758..dfb1a4c8c4e89 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -10716,19 +10716,18 @@ namespace ts { return result; } } - let constraint = getConstraintForRelation(source); - // A type variable with no constraint is not related to the non-primitive object type. - if (constraint || !(target.flags & TypeFlags.NonPrimitive)) { - if (!constraint || constraint.flags & TypeFlags.Any) { - constraint = emptyObjectType; - } - // Report constraint errors only if the constraint is not the empty object type - const reportConstraintErrors = reportErrors && constraint !== emptyObjectType; - if (result = isRelatedTo(constraint, target, reportConstraintErrors)) { + const constraint = getConstraintForRelation(source); + if (!constraint || constraint.flags & TypeFlags.Any) { + // A type variable with no constraint is not related to the non-primitive object type. + if (result = isRelatedTo(emptyObjectType, extractTypesOfKind(target, ~TypeFlags.NonPrimitive))) { errorInfo = saveErrorInfo; return result; } } + else if (result = isRelatedTo(constraint, target, reportErrors)) { + errorInfo = saveErrorInfo; + return result; + } } else if (source.flags & TypeFlags.Index) { if (result = isRelatedTo(keyofConstraintType, target, reportErrors)) { diff --git a/tests/baselines/reference/nonPrimitiveAndTypeVariables.errors.txt b/tests/baselines/reference/nonPrimitiveAndTypeVariables.errors.txt new file mode 100644 index 0000000000000..83ce98f1cd625 --- /dev/null +++ b/tests/baselines/reference/nonPrimitiveAndTypeVariables.errors.txt @@ -0,0 +1,24 @@ +tests/cases/conformance/types/nonPrimitive/nonPrimitiveAndTypeVariables.ts(10,9): error TS2322: Type 'T' is not assignable to type 'object'. +tests/cases/conformance/types/nonPrimitive/nonPrimitiveAndTypeVariables.ts(11,9): error TS2322: Type 'T' is not assignable to type 'object | U'. + Type 'T' is not assignable to type 'U'. + + +==== tests/cases/conformance/types/nonPrimitive/nonPrimitiveAndTypeVariables.ts (2 errors) ==== + // Repros from #23800 + + type A = { [P in keyof T]: T[P] extends V ? 1 : 0; }; + type B = { [P in keyof T]: T[P] extends V | object ? 1 : 0; }; + + let a: A<{ a: 0 | 1 }, 0> = { a: 0 }; + let b: B<{ a: 0 | 1 }, 0> = { a: 0 }; + + function foo(x: T) { + let a: object = x; // Error + ~ +!!! error TS2322: Type 'T' is not assignable to type 'object'. + let b: U | object = x; // Error + ~ +!!! error TS2322: Type 'T' is not assignable to type 'object | U'. +!!! error TS2322: Type 'T' is not assignable to type 'U'. + } + \ No newline at end of file diff --git a/tests/baselines/reference/nonPrimitiveAndTypeVariables.js b/tests/baselines/reference/nonPrimitiveAndTypeVariables.js new file mode 100644 index 0000000000000..fda272c1fe26d --- /dev/null +++ b/tests/baselines/reference/nonPrimitiveAndTypeVariables.js @@ -0,0 +1,24 @@ +//// [nonPrimitiveAndTypeVariables.ts] +// Repros from #23800 + +type A = { [P in keyof T]: T[P] extends V ? 1 : 0; }; +type B = { [P in keyof T]: T[P] extends V | object ? 1 : 0; }; + +let a: A<{ a: 0 | 1 }, 0> = { a: 0 }; +let b: B<{ a: 0 | 1 }, 0> = { a: 0 }; + +function foo(x: T) { + let a: object = x; // Error + let b: U | object = x; // Error +} + + +//// [nonPrimitiveAndTypeVariables.js] +"use strict"; +// Repros from #23800 +var a = { a: 0 }; +var b = { a: 0 }; +function foo(x) { + var a = x; // Error + var b = x; // Error +} diff --git a/tests/baselines/reference/nonPrimitiveAndTypeVariables.symbols b/tests/baselines/reference/nonPrimitiveAndTypeVariables.symbols new file mode 100644 index 0000000000000..083c67e7fdb23 --- /dev/null +++ b/tests/baselines/reference/nonPrimitiveAndTypeVariables.symbols @@ -0,0 +1,52 @@ +=== tests/cases/conformance/types/nonPrimitive/nonPrimitiveAndTypeVariables.ts === +// Repros from #23800 + +type A = { [P in keyof T]: T[P] extends V ? 1 : 0; }; +>A : Symbol(A, Decl(nonPrimitiveAndTypeVariables.ts, 0, 0)) +>T : Symbol(T, Decl(nonPrimitiveAndTypeVariables.ts, 2, 7)) +>V : Symbol(V, Decl(nonPrimitiveAndTypeVariables.ts, 2, 9)) +>P : Symbol(P, Decl(nonPrimitiveAndTypeVariables.ts, 2, 18)) +>T : Symbol(T, Decl(nonPrimitiveAndTypeVariables.ts, 2, 7)) +>T : Symbol(T, Decl(nonPrimitiveAndTypeVariables.ts, 2, 7)) +>P : Symbol(P, Decl(nonPrimitiveAndTypeVariables.ts, 2, 18)) +>V : Symbol(V, Decl(nonPrimitiveAndTypeVariables.ts, 2, 9)) + +type B = { [P in keyof T]: T[P] extends V | object ? 1 : 0; }; +>B : Symbol(B, Decl(nonPrimitiveAndTypeVariables.ts, 2, 59)) +>T : Symbol(T, Decl(nonPrimitiveAndTypeVariables.ts, 3, 7)) +>V : Symbol(V, Decl(nonPrimitiveAndTypeVariables.ts, 3, 9)) +>P : Symbol(P, Decl(nonPrimitiveAndTypeVariables.ts, 3, 18)) +>T : Symbol(T, Decl(nonPrimitiveAndTypeVariables.ts, 3, 7)) +>T : Symbol(T, Decl(nonPrimitiveAndTypeVariables.ts, 3, 7)) +>P : Symbol(P, Decl(nonPrimitiveAndTypeVariables.ts, 3, 18)) +>V : Symbol(V, Decl(nonPrimitiveAndTypeVariables.ts, 3, 9)) + +let a: A<{ a: 0 | 1 }, 0> = { a: 0 }; +>a : Symbol(a, Decl(nonPrimitiveAndTypeVariables.ts, 5, 3)) +>A : Symbol(A, Decl(nonPrimitiveAndTypeVariables.ts, 0, 0)) +>a : Symbol(a, Decl(nonPrimitiveAndTypeVariables.ts, 5, 10)) +>a : Symbol(a, Decl(nonPrimitiveAndTypeVariables.ts, 5, 29)) + +let b: B<{ a: 0 | 1 }, 0> = { a: 0 }; +>b : Symbol(b, Decl(nonPrimitiveAndTypeVariables.ts, 6, 3)) +>B : Symbol(B, Decl(nonPrimitiveAndTypeVariables.ts, 2, 59)) +>a : Symbol(a, Decl(nonPrimitiveAndTypeVariables.ts, 6, 10)) +>a : Symbol(a, Decl(nonPrimitiveAndTypeVariables.ts, 6, 29)) + +function foo(x: T) { +>foo : Symbol(foo, Decl(nonPrimitiveAndTypeVariables.ts, 6, 37)) +>T : Symbol(T, Decl(nonPrimitiveAndTypeVariables.ts, 8, 13)) +>U : Symbol(U, Decl(nonPrimitiveAndTypeVariables.ts, 8, 15)) +>x : Symbol(x, Decl(nonPrimitiveAndTypeVariables.ts, 8, 19)) +>T : Symbol(T, Decl(nonPrimitiveAndTypeVariables.ts, 8, 13)) + + let a: object = x; // Error +>a : Symbol(a, Decl(nonPrimitiveAndTypeVariables.ts, 9, 7)) +>x : Symbol(x, Decl(nonPrimitiveAndTypeVariables.ts, 8, 19)) + + let b: U | object = x; // Error +>b : Symbol(b, Decl(nonPrimitiveAndTypeVariables.ts, 10, 7)) +>U : Symbol(U, Decl(nonPrimitiveAndTypeVariables.ts, 8, 15)) +>x : Symbol(x, Decl(nonPrimitiveAndTypeVariables.ts, 8, 19)) +} + diff --git a/tests/baselines/reference/nonPrimitiveAndTypeVariables.types b/tests/baselines/reference/nonPrimitiveAndTypeVariables.types new file mode 100644 index 0000000000000..f2fba1201407f --- /dev/null +++ b/tests/baselines/reference/nonPrimitiveAndTypeVariables.types @@ -0,0 +1,56 @@ +=== tests/cases/conformance/types/nonPrimitive/nonPrimitiveAndTypeVariables.ts === +// Repros from #23800 + +type A = { [P in keyof T]: T[P] extends V ? 1 : 0; }; +>A : A +>T : T +>V : V +>P : P +>T : T +>T : T +>P : P +>V : V + +type B = { [P in keyof T]: T[P] extends V | object ? 1 : 0; }; +>B : B +>T : T +>V : V +>P : P +>T : T +>T : T +>P : P +>V : V + +let a: A<{ a: 0 | 1 }, 0> = { a: 0 }; +>a : A<{ a: 0 | 1; }, 0> +>A : A +>a : 0 | 1 +>{ a: 0 } : { a: 0; } +>a : 0 +>0 : 0 + +let b: B<{ a: 0 | 1 }, 0> = { a: 0 }; +>b : B<{ a: 0 | 1; }, 0> +>B : B +>a : 0 | 1 +>{ a: 0 } : { a: 0; } +>a : 0 +>0 : 0 + +function foo(x: T) { +>foo : (x: T) => void +>T : T +>U : U +>x : T +>T : T + + let a: object = x; // Error +>a : object +>x : T + + let b: U | object = x; // Error +>b : object | U +>U : U +>x : T +} + diff --git a/tests/cases/conformance/types/nonPrimitive/nonPrimitiveAndTypeVariables.ts b/tests/cases/conformance/types/nonPrimitive/nonPrimitiveAndTypeVariables.ts new file mode 100644 index 0000000000000..a0eeec2cdd762 --- /dev/null +++ b/tests/cases/conformance/types/nonPrimitive/nonPrimitiveAndTypeVariables.ts @@ -0,0 +1,14 @@ +// @strict: true + +// Repros from #23800 + +type A = { [P in keyof T]: T[P] extends V ? 1 : 0; }; +type B = { [P in keyof T]: T[P] extends V | object ? 1 : 0; }; + +let a: A<{ a: 0 | 1 }, 0> = { a: 0 }; +let b: B<{ a: 0 | 1 }, 0> = { a: 0 }; + +function foo(x: T) { + let a: object = x; // Error + let b: U | object = x; // Error +}