diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 0b67afefbb9d8..9fe2aede6415c 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -17115,11 +17115,6 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return extractTypeAlias ? getTypeAliasInstantiation(extractTypeAlias, [type, stringType]) : stringType; } - function getIndexTypeOrString(type: Type): Type { - const indexType = getExtractStringType(getIndexType(type)); - return indexType.flags & TypeFlags.Never ? stringType : indexType; - } - function getTypeFromTypeOperatorNode(node: TypeOperatorNode): Type { const links = getNodeLinks(node); if (!links.resolvedType) { @@ -41554,7 +41549,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (varExpr.kind === SyntaxKind.ArrayLiteralExpression || varExpr.kind === SyntaxKind.ObjectLiteralExpression) { error(varExpr, Diagnostics.The_left_hand_side_of_a_for_in_statement_cannot_be_a_destructuring_pattern); } - else if (!isTypeAssignableTo(getIndexTypeOrString(rightType), leftType)) { + else if (!isTypeAssignableTo(stringType, leftType)) { error(varExpr, Diagnostics.The_left_hand_side_of_a_for_in_statement_must_be_of_type_string_or_any); } else { diff --git a/tests/baselines/reference/forIn3.errors.txt b/tests/baselines/reference/forIn3.errors.txt new file mode 100644 index 0000000000000..d58e0505015ee --- /dev/null +++ b/tests/baselines/reference/forIn3.errors.txt @@ -0,0 +1,11 @@ +forIn3.ts(3,8): error TS2405: The left-hand side of a 'for...in' statement must be of type 'string' or 'any'. + + +==== forIn3.ts (1 errors) ==== + function test(obj: { a: 1; b: 2 }) { + let key: "a" | "b"; + for (key in obj) {} // error + ~~~ +!!! error TS2405: The left-hand side of a 'for...in' statement must be of type 'string' or 'any'. + } + \ No newline at end of file diff --git a/tests/baselines/reference/forIn3.symbols b/tests/baselines/reference/forIn3.symbols new file mode 100644 index 0000000000000..4ad6cfd796719 --- /dev/null +++ b/tests/baselines/reference/forIn3.symbols @@ -0,0 +1,17 @@ +//// [tests/cases/compiler/forIn3.ts] //// + +=== forIn3.ts === +function test(obj: { a: 1; b: 2 }) { +>test : Symbol(test, Decl(forIn3.ts, 0, 0)) +>obj : Symbol(obj, Decl(forIn3.ts, 0, 14)) +>a : Symbol(a, Decl(forIn3.ts, 0, 20)) +>b : Symbol(b, Decl(forIn3.ts, 0, 26)) + + let key: "a" | "b"; +>key : Symbol(key, Decl(forIn3.ts, 1, 5)) + + for (key in obj) {} // error +>key : Symbol(key, Decl(forIn3.ts, 1, 5)) +>obj : Symbol(obj, Decl(forIn3.ts, 0, 14)) +} + diff --git a/tests/baselines/reference/forIn3.types b/tests/baselines/reference/forIn3.types new file mode 100644 index 0000000000000..b93fc5385b4ac --- /dev/null +++ b/tests/baselines/reference/forIn3.types @@ -0,0 +1,17 @@ +//// [tests/cases/compiler/forIn3.ts] //// + +=== forIn3.ts === +function test(obj: { a: 1; b: 2 }) { +>test : (obj: { a: 1; b: 2;}) => void +>obj : { a: 1; b: 2; } +>a : 1 +>b : 2 + + let key: "a" | "b"; +>key : "a" | "b" + + for (key in obj) {} // error +>key : "a" | "b" +>obj : { a: 1; b: 2; } +} + diff --git a/tests/baselines/reference/keyofAndForIn.errors.txt b/tests/baselines/reference/keyofAndForIn.errors.txt new file mode 100644 index 0000000000000..83857325ce2b1 --- /dev/null +++ b/tests/baselines/reference/keyofAndForIn.errors.txt @@ -0,0 +1,44 @@ +keyofAndForIn.ts(4,10): error TS2405: The left-hand side of a 'for...in' statement must be of type 'string' or 'any'. +keyofAndForIn.ts(15,10): error TS2405: The left-hand side of a 'for...in' statement must be of type 'string' or 'any'. +keyofAndForIn.ts(26,10): error TS2405: The left-hand side of a 'for...in' statement must be of type 'string' or 'any'. + + +==== keyofAndForIn.ts (3 errors) ==== + function f1(obj: { [P in K]: T }, k: K) { + const b = k in obj; + let k1: K; + for (k1 in obj) { + ~~ +!!! error TS2405: The left-hand side of a 'for...in' statement must be of type 'string' or 'any'. + let x1 = obj[k1]; + } + for (let k2 in obj) { + let x2 = obj[k2]; + } + } + + function f2(obj: { [P in keyof T]: T[P] }, k: keyof T) { + const b = k in obj; + let k1: keyof T; + for (k1 in obj) { + ~~ +!!! error TS2405: The left-hand side of a 'for...in' statement must be of type 'string' or 'any'. + let x1 = obj[k1]; + } + for (let k2 in obj) { + let x2 = obj[k2]; + } + } + + function f3(obj: { [P in K]: T[P] }, k: K) { + const b = k in obj; + let k1: K; + for (k1 in obj) { + ~~ +!!! error TS2405: The left-hand side of a 'for...in' statement must be of type 'string' or 'any'. + let x1 = obj[k1]; + } + for (let k2 in obj) { + let x2 = obj[k2]; + } + } \ No newline at end of file diff --git a/tests/baselines/reference/keyofAndForIn.js b/tests/baselines/reference/keyofAndForIn.js index 5373b0f0783a1..5a0a34412395f 100644 --- a/tests/baselines/reference/keyofAndForIn.js +++ b/tests/baselines/reference/keyofAndForIn.js @@ -1,8 +1,6 @@ //// [tests/cases/conformance/types/keyof/keyofAndForIn.ts] //// //// [keyofAndForIn.ts] -// Repro from #12513 - function f1(obj: { [P in K]: T }, k: K) { const b = k in obj; let k1: K; @@ -37,7 +35,6 @@ function f3(obj: { [P in K]: T[P] }, k: K) { } //// [keyofAndForIn.js] -// Repro from #12513 function f1(obj, k) { var b = k in obj; var k1; diff --git a/tests/baselines/reference/keyofAndForIn.symbols b/tests/baselines/reference/keyofAndForIn.symbols index a912d6029a39c..1848e4706cc95 100644 --- a/tests/baselines/reference/keyofAndForIn.symbols +++ b/tests/baselines/reference/keyofAndForIn.symbols @@ -1,126 +1,124 @@ //// [tests/cases/conformance/types/keyof/keyofAndForIn.ts] //// === keyofAndForIn.ts === -// Repro from #12513 - function f1(obj: { [P in K]: T }, k: K) { >f1 : Symbol(f1, Decl(keyofAndForIn.ts, 0, 0)) ->K : Symbol(K, Decl(keyofAndForIn.ts, 2, 12)) ->T : Symbol(T, Decl(keyofAndForIn.ts, 2, 29)) ->obj : Symbol(obj, Decl(keyofAndForIn.ts, 2, 33)) ->P : Symbol(P, Decl(keyofAndForIn.ts, 2, 41)) ->K : Symbol(K, Decl(keyofAndForIn.ts, 2, 12)) ->T : Symbol(T, Decl(keyofAndForIn.ts, 2, 29)) ->k : Symbol(k, Decl(keyofAndForIn.ts, 2, 54)) ->K : Symbol(K, Decl(keyofAndForIn.ts, 2, 12)) +>K : Symbol(K, Decl(keyofAndForIn.ts, 0, 12)) +>T : Symbol(T, Decl(keyofAndForIn.ts, 0, 29)) +>obj : Symbol(obj, Decl(keyofAndForIn.ts, 0, 33)) +>P : Symbol(P, Decl(keyofAndForIn.ts, 0, 41)) +>K : Symbol(K, Decl(keyofAndForIn.ts, 0, 12)) +>T : Symbol(T, Decl(keyofAndForIn.ts, 0, 29)) +>k : Symbol(k, Decl(keyofAndForIn.ts, 0, 54)) +>K : Symbol(K, Decl(keyofAndForIn.ts, 0, 12)) const b = k in obj; ->b : Symbol(b, Decl(keyofAndForIn.ts, 3, 9)) ->k : Symbol(k, Decl(keyofAndForIn.ts, 2, 54)) ->obj : Symbol(obj, Decl(keyofAndForIn.ts, 2, 33)) +>b : Symbol(b, Decl(keyofAndForIn.ts, 1, 9)) +>k : Symbol(k, Decl(keyofAndForIn.ts, 0, 54)) +>obj : Symbol(obj, Decl(keyofAndForIn.ts, 0, 33)) let k1: K; ->k1 : Symbol(k1, Decl(keyofAndForIn.ts, 4, 7)) ->K : Symbol(K, Decl(keyofAndForIn.ts, 2, 12)) +>k1 : Symbol(k1, Decl(keyofAndForIn.ts, 2, 7)) +>K : Symbol(K, Decl(keyofAndForIn.ts, 0, 12)) for (k1 in obj) { ->k1 : Symbol(k1, Decl(keyofAndForIn.ts, 4, 7)) ->obj : Symbol(obj, Decl(keyofAndForIn.ts, 2, 33)) +>k1 : Symbol(k1, Decl(keyofAndForIn.ts, 2, 7)) +>obj : Symbol(obj, Decl(keyofAndForIn.ts, 0, 33)) let x1 = obj[k1]; ->x1 : Symbol(x1, Decl(keyofAndForIn.ts, 6, 11)) ->obj : Symbol(obj, Decl(keyofAndForIn.ts, 2, 33)) ->k1 : Symbol(k1, Decl(keyofAndForIn.ts, 4, 7)) +>x1 : Symbol(x1, Decl(keyofAndForIn.ts, 4, 11)) +>obj : Symbol(obj, Decl(keyofAndForIn.ts, 0, 33)) +>k1 : Symbol(k1, Decl(keyofAndForIn.ts, 2, 7)) } for (let k2 in obj) { ->k2 : Symbol(k2, Decl(keyofAndForIn.ts, 8, 12)) ->obj : Symbol(obj, Decl(keyofAndForIn.ts, 2, 33)) +>k2 : Symbol(k2, Decl(keyofAndForIn.ts, 6, 12)) +>obj : Symbol(obj, Decl(keyofAndForIn.ts, 0, 33)) let x2 = obj[k2]; ->x2 : Symbol(x2, Decl(keyofAndForIn.ts, 9, 11)) ->obj : Symbol(obj, Decl(keyofAndForIn.ts, 2, 33)) ->k2 : Symbol(k2, Decl(keyofAndForIn.ts, 8, 12)) +>x2 : Symbol(x2, Decl(keyofAndForIn.ts, 7, 11)) +>obj : Symbol(obj, Decl(keyofAndForIn.ts, 0, 33)) +>k2 : Symbol(k2, Decl(keyofAndForIn.ts, 6, 12)) } } function f2(obj: { [P in keyof T]: T[P] }, k: keyof T) { ->f2 : Symbol(f2, Decl(keyofAndForIn.ts, 11, 1)) ->T : Symbol(T, Decl(keyofAndForIn.ts, 13, 12)) ->obj : Symbol(obj, Decl(keyofAndForIn.ts, 13, 15)) ->P : Symbol(P, Decl(keyofAndForIn.ts, 13, 23)) ->T : Symbol(T, Decl(keyofAndForIn.ts, 13, 12)) ->T : Symbol(T, Decl(keyofAndForIn.ts, 13, 12)) ->P : Symbol(P, Decl(keyofAndForIn.ts, 13, 23)) ->k : Symbol(k, Decl(keyofAndForIn.ts, 13, 45)) ->T : Symbol(T, Decl(keyofAndForIn.ts, 13, 12)) +>f2 : Symbol(f2, Decl(keyofAndForIn.ts, 9, 1)) +>T : Symbol(T, Decl(keyofAndForIn.ts, 11, 12)) +>obj : Symbol(obj, Decl(keyofAndForIn.ts, 11, 15)) +>P : Symbol(P, Decl(keyofAndForIn.ts, 11, 23)) +>T : Symbol(T, Decl(keyofAndForIn.ts, 11, 12)) +>T : Symbol(T, Decl(keyofAndForIn.ts, 11, 12)) +>P : Symbol(P, Decl(keyofAndForIn.ts, 11, 23)) +>k : Symbol(k, Decl(keyofAndForIn.ts, 11, 45)) +>T : Symbol(T, Decl(keyofAndForIn.ts, 11, 12)) const b = k in obj; ->b : Symbol(b, Decl(keyofAndForIn.ts, 14, 9)) ->k : Symbol(k, Decl(keyofAndForIn.ts, 13, 45)) ->obj : Symbol(obj, Decl(keyofAndForIn.ts, 13, 15)) +>b : Symbol(b, Decl(keyofAndForIn.ts, 12, 9)) +>k : Symbol(k, Decl(keyofAndForIn.ts, 11, 45)) +>obj : Symbol(obj, Decl(keyofAndForIn.ts, 11, 15)) let k1: keyof T; ->k1 : Symbol(k1, Decl(keyofAndForIn.ts, 15, 7)) ->T : Symbol(T, Decl(keyofAndForIn.ts, 13, 12)) +>k1 : Symbol(k1, Decl(keyofAndForIn.ts, 13, 7)) +>T : Symbol(T, Decl(keyofAndForIn.ts, 11, 12)) for (k1 in obj) { ->k1 : Symbol(k1, Decl(keyofAndForIn.ts, 15, 7)) ->obj : Symbol(obj, Decl(keyofAndForIn.ts, 13, 15)) +>k1 : Symbol(k1, Decl(keyofAndForIn.ts, 13, 7)) +>obj : Symbol(obj, Decl(keyofAndForIn.ts, 11, 15)) let x1 = obj[k1]; ->x1 : Symbol(x1, Decl(keyofAndForIn.ts, 17, 11)) ->obj : Symbol(obj, Decl(keyofAndForIn.ts, 13, 15)) ->k1 : Symbol(k1, Decl(keyofAndForIn.ts, 15, 7)) +>x1 : Symbol(x1, Decl(keyofAndForIn.ts, 15, 11)) +>obj : Symbol(obj, Decl(keyofAndForIn.ts, 11, 15)) +>k1 : Symbol(k1, Decl(keyofAndForIn.ts, 13, 7)) } for (let k2 in obj) { ->k2 : Symbol(k2, Decl(keyofAndForIn.ts, 19, 12)) ->obj : Symbol(obj, Decl(keyofAndForIn.ts, 13, 15)) +>k2 : Symbol(k2, Decl(keyofAndForIn.ts, 17, 12)) +>obj : Symbol(obj, Decl(keyofAndForIn.ts, 11, 15)) let x2 = obj[k2]; ->x2 : Symbol(x2, Decl(keyofAndForIn.ts, 20, 11)) ->obj : Symbol(obj, Decl(keyofAndForIn.ts, 13, 15)) ->k2 : Symbol(k2, Decl(keyofAndForIn.ts, 19, 12)) +>x2 : Symbol(x2, Decl(keyofAndForIn.ts, 18, 11)) +>obj : Symbol(obj, Decl(keyofAndForIn.ts, 11, 15)) +>k2 : Symbol(k2, Decl(keyofAndForIn.ts, 17, 12)) } } function f3(obj: { [P in K]: T[P] }, k: K) { ->f3 : Symbol(f3, Decl(keyofAndForIn.ts, 22, 1)) ->T : Symbol(T, Decl(keyofAndForIn.ts, 24, 12)) ->K : Symbol(K, Decl(keyofAndForIn.ts, 24, 14)) ->T : Symbol(T, Decl(keyofAndForIn.ts, 24, 12)) ->obj : Symbol(obj, Decl(keyofAndForIn.ts, 24, 34)) ->P : Symbol(P, Decl(keyofAndForIn.ts, 24, 42)) ->K : Symbol(K, Decl(keyofAndForIn.ts, 24, 14)) ->T : Symbol(T, Decl(keyofAndForIn.ts, 24, 12)) ->P : Symbol(P, Decl(keyofAndForIn.ts, 24, 42)) ->k : Symbol(k, Decl(keyofAndForIn.ts, 24, 58)) ->K : Symbol(K, Decl(keyofAndForIn.ts, 24, 14)) +>f3 : Symbol(f3, Decl(keyofAndForIn.ts, 20, 1)) +>T : Symbol(T, Decl(keyofAndForIn.ts, 22, 12)) +>K : Symbol(K, Decl(keyofAndForIn.ts, 22, 14)) +>T : Symbol(T, Decl(keyofAndForIn.ts, 22, 12)) +>obj : Symbol(obj, Decl(keyofAndForIn.ts, 22, 34)) +>P : Symbol(P, Decl(keyofAndForIn.ts, 22, 42)) +>K : Symbol(K, Decl(keyofAndForIn.ts, 22, 14)) +>T : Symbol(T, Decl(keyofAndForIn.ts, 22, 12)) +>P : Symbol(P, Decl(keyofAndForIn.ts, 22, 42)) +>k : Symbol(k, Decl(keyofAndForIn.ts, 22, 58)) +>K : Symbol(K, Decl(keyofAndForIn.ts, 22, 14)) const b = k in obj; ->b : Symbol(b, Decl(keyofAndForIn.ts, 25, 9)) ->k : Symbol(k, Decl(keyofAndForIn.ts, 24, 58)) ->obj : Symbol(obj, Decl(keyofAndForIn.ts, 24, 34)) +>b : Symbol(b, Decl(keyofAndForIn.ts, 23, 9)) +>k : Symbol(k, Decl(keyofAndForIn.ts, 22, 58)) +>obj : Symbol(obj, Decl(keyofAndForIn.ts, 22, 34)) let k1: K; ->k1 : Symbol(k1, Decl(keyofAndForIn.ts, 26, 7)) ->K : Symbol(K, Decl(keyofAndForIn.ts, 24, 14)) +>k1 : Symbol(k1, Decl(keyofAndForIn.ts, 24, 7)) +>K : Symbol(K, Decl(keyofAndForIn.ts, 22, 14)) for (k1 in obj) { ->k1 : Symbol(k1, Decl(keyofAndForIn.ts, 26, 7)) ->obj : Symbol(obj, Decl(keyofAndForIn.ts, 24, 34)) +>k1 : Symbol(k1, Decl(keyofAndForIn.ts, 24, 7)) +>obj : Symbol(obj, Decl(keyofAndForIn.ts, 22, 34)) let x1 = obj[k1]; ->x1 : Symbol(x1, Decl(keyofAndForIn.ts, 28, 11)) ->obj : Symbol(obj, Decl(keyofAndForIn.ts, 24, 34)) ->k1 : Symbol(k1, Decl(keyofAndForIn.ts, 26, 7)) +>x1 : Symbol(x1, Decl(keyofAndForIn.ts, 26, 11)) +>obj : Symbol(obj, Decl(keyofAndForIn.ts, 22, 34)) +>k1 : Symbol(k1, Decl(keyofAndForIn.ts, 24, 7)) } for (let k2 in obj) { ->k2 : Symbol(k2, Decl(keyofAndForIn.ts, 30, 12)) ->obj : Symbol(obj, Decl(keyofAndForIn.ts, 24, 34)) +>k2 : Symbol(k2, Decl(keyofAndForIn.ts, 28, 12)) +>obj : Symbol(obj, Decl(keyofAndForIn.ts, 22, 34)) let x2 = obj[k2]; ->x2 : Symbol(x2, Decl(keyofAndForIn.ts, 31, 11)) ->obj : Symbol(obj, Decl(keyofAndForIn.ts, 24, 34)) ->k2 : Symbol(k2, Decl(keyofAndForIn.ts, 30, 12)) +>x2 : Symbol(x2, Decl(keyofAndForIn.ts, 29, 11)) +>obj : Symbol(obj, Decl(keyofAndForIn.ts, 22, 34)) +>k2 : Symbol(k2, Decl(keyofAndForIn.ts, 28, 12)) } } diff --git a/tests/baselines/reference/keyofAndForIn.types b/tests/baselines/reference/keyofAndForIn.types index 96411eb419438..ac50347e1d920 100644 --- a/tests/baselines/reference/keyofAndForIn.types +++ b/tests/baselines/reference/keyofAndForIn.types @@ -1,8 +1,6 @@ //// [tests/cases/conformance/types/keyof/keyofAndForIn.ts] //// === keyofAndForIn.ts === -// Repro from #12513 - function f1(obj: { [P in K]: T }, k: K) { >f1 : (obj: { [P in K]: T; }, k: K) => void >obj : { [P in K]: T; } diff --git a/tests/cases/compiler/forIn3.ts b/tests/cases/compiler/forIn3.ts new file mode 100644 index 0000000000000..31cc529cc180e --- /dev/null +++ b/tests/cases/compiler/forIn3.ts @@ -0,0 +1,7 @@ +// @strict: true +// @noEmit: true + +function test(obj: { a: 1; b: 2 }) { + let key: "a" | "b"; + for (key in obj) {} // error +} diff --git a/tests/cases/conformance/types/keyof/keyofAndForIn.ts b/tests/cases/conformance/types/keyof/keyofAndForIn.ts index 97b8587a24326..33e5c575cbd75 100644 --- a/tests/cases/conformance/types/keyof/keyofAndForIn.ts +++ b/tests/cases/conformance/types/keyof/keyofAndForIn.ts @@ -1,7 +1,5 @@ // @declaration: true -// Repro from #12513 - function f1(obj: { [P in K]: T }, k: K) { const b = k in obj; let k1: K;