diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 47a5c6950d2..6778bacd05a 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -7576,7 +7576,6 @@ namespace ts { if (indexInfo) { if (accessExpression && indexInfo.isReadonly && (isAssignmentTarget(accessExpression) || isDeleteTarget(accessExpression))) { error(accessExpression, Diagnostics.Index_signature_in_type_0_only_permits_reading, typeToString(objectType)); - return unknownType; } return indexInfo.type; } @@ -7617,7 +7616,6 @@ namespace ts { } if (accessNode.kind === SyntaxKind.ElementAccessExpression && isAssignmentTarget(accessNode) && type.declaration.readonlyToken) { error(accessNode, Diagnostics.Index_signature_in_type_0_only_permits_reading, typeToString(type)); - return unknownType; } } const mapper = createTypeMapper([getTypeParameterFromMappedType(type)], [indexType]); @@ -14615,9 +14613,12 @@ namespace ts { } const prop = getPropertyOfType(apparentType, right.escapedText); if (!prop) { - const stringIndexType = getIndexTypeOfType(apparentType, IndexKind.String); - if (stringIndexType) { - return stringIndexType; + const indexInfo = getIndexInfoOfType(apparentType, IndexKind.String); + if (indexInfo && indexInfo.type) { + if (indexInfo.isReadonly && (isAssignmentTarget(node) || isDeleteTarget(node))) { + error(node, Diagnostics.Index_signature_in_type_0_only_permits_reading, typeToString(apparentType)); + } + return indexInfo.type; } if (right.escapedText && !checkAndReportErrorForExtendingInterface(node)) { reportNonexistentProperty(right, type.flags & TypeFlags.TypeParameter && (type as TypeParameter).isThisType ? apparentType : type); @@ -17138,7 +17139,9 @@ namespace ts { if (operandType === silentNeverType) { return silentNeverType; } - const ok = checkArithmeticOperandType(node.operand, checkNonNullType(operandType, node.operand), + const ok = checkArithmeticOperandType( + node.operand, + checkNonNullType(operandType, node.operand), Diagnostics.An_arithmetic_operand_must_be_of_type_any_number_or_an_enum_type); if (ok) { // run check only if former checks succeeded to avoid reporting cascading errors diff --git a/tests/baselines/reference/decrementOperatorWithEnumType.errors.txt b/tests/baselines/reference/decrementOperatorWithEnumType.errors.txt index aae28d5e417..284e15c5193 100644 --- a/tests/baselines/reference/decrementOperatorWithEnumType.errors.txt +++ b/tests/baselines/reference/decrementOperatorWithEnumType.errors.txt @@ -1,11 +1,12 @@ tests/cases/conformance/expressions/unaryOperators/decrementOperator/decrementOperatorWithEnumType.ts(6,31): error TS2540: Cannot assign to 'A' because it is a constant or a read-only property. tests/cases/conformance/expressions/unaryOperators/decrementOperator/decrementOperatorWithEnumType.ts(7,29): error TS2540: Cannot assign to 'A' because it is a constant or a read-only property. tests/cases/conformance/expressions/unaryOperators/decrementOperator/decrementOperatorWithEnumType.ts(10,9): error TS2540: Cannot assign to 'A' because it is a constant or a read-only property. +tests/cases/conformance/expressions/unaryOperators/decrementOperator/decrementOperatorWithEnumType.ts(12,1): error TS2356: An arithmetic operand must be of type 'any', 'number' or an enum type. tests/cases/conformance/expressions/unaryOperators/decrementOperator/decrementOperatorWithEnumType.ts(12,1): error TS2542: Index signature in type 'typeof ENUM1' only permits reading. tests/cases/conformance/expressions/unaryOperators/decrementOperator/decrementOperatorWithEnumType.ts(12,7): error TS2304: Cannot find name 'A'. -==== tests/cases/conformance/expressions/unaryOperators/decrementOperator/decrementOperatorWithEnumType.ts (5 errors) ==== +==== tests/cases/conformance/expressions/unaryOperators/decrementOperator/decrementOperatorWithEnumType.ts (6 errors) ==== // -- operator on enum type enum ENUM1 { A, B, "" }; @@ -25,6 +26,9 @@ tests/cases/conformance/expressions/unaryOperators/decrementOperator/decrementOp ENUM1[A]--; ~~~~~~~~ +!!! error TS2356: An arithmetic operand must be of type 'any', 'number' or an enum type. + ~~~~~~~~ !!! error TS2542: Index signature in type 'typeof ENUM1' only permits reading. ~ -!!! error TS2304: Cannot find name 'A'. \ No newline at end of file +!!! error TS2304: Cannot find name 'A'. + \ No newline at end of file diff --git a/tests/baselines/reference/decrementOperatorWithEnumType.js b/tests/baselines/reference/decrementOperatorWithEnumType.js index 27cb376cc05..306482faf31 100644 --- a/tests/baselines/reference/decrementOperatorWithEnumType.js +++ b/tests/baselines/reference/decrementOperatorWithEnumType.js @@ -10,7 +10,8 @@ var ResultIsNumber2 = ENUM1.A--; // miss assignment operator --ENUM1["A"]; -ENUM1[A]--; +ENUM1[A]--; + //// [decrementOperatorWithEnumType.js] // -- operator on enum type diff --git a/tests/baselines/reference/mappedTypeRelationships.errors.txt b/tests/baselines/reference/mappedTypeRelationships.errors.txt index bc0aa32b149..a1e1455b419 100644 --- a/tests/baselines/reference/mappedTypeRelationships.errors.txt +++ b/tests/baselines/reference/mappedTypeRelationships.errors.txt @@ -58,7 +58,19 @@ tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(46,5): error TS2 Type 'T' is not assignable to type 'U'. tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(51,5): error TS2542: Index signature in type 'Readonly' only permits reading. tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(56,5): error TS2542: Index signature in type 'Readonly' only permits reading. +tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(61,5): error TS2322: Type 'T[keyof T]' is not assignable to type 'U[keyof T]'. + Type 'T[string]' is not assignable to type 'U[keyof T]'. + Type 'T[string]' is not assignable to type 'U[string]'. + Type 'T[keyof T]' is not assignable to type 'U[string]'. + Type 'T[string]' is not assignable to type 'U[string]'. + Type 'T' is not assignable to type 'U'. tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(61,5): error TS2542: Index signature in type 'Readonly' only permits reading. +tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(66,5): error TS2322: Type 'T[K]' is not assignable to type 'U[K]'. + Type 'T[string]' is not assignable to type 'U[K]'. + Type 'T[string]' is not assignable to type 'U[string]'. + Type 'T[K]' is not assignable to type 'U[string]'. + Type 'T[string]' is not assignable to type 'U[string]'. + Type 'T' is not assignable to type 'U'. tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(66,5): error TS2542: Index signature in type 'Readonly' only permits reading. tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(72,5): error TS2322: Type 'Partial' is not assignable to type 'T'. tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(78,5): error TS2322: Type 'Partial' is not assignable to type 'Partial'. @@ -88,7 +100,7 @@ tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(168,5): error TS Type 'T' is not assignable to type 'U'. -==== tests/cases/conformance/types/mapped/mappedTypeRelationships.ts (28 errors) ==== +==== tests/cases/conformance/types/mapped/mappedTypeRelationships.ts (30 errors) ==== function f1(x: T, k: keyof T) { return x[k]; } @@ -227,6 +239,13 @@ tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(168,5): error TS x[k] = y[k]; y[k] = x[k]; // Error ~~~~ +!!! error TS2322: Type 'T[keyof T]' is not assignable to type 'U[keyof T]'. +!!! error TS2322: Type 'T[string]' is not assignable to type 'U[keyof T]'. +!!! error TS2322: Type 'T[string]' is not assignable to type 'U[string]'. +!!! error TS2322: Type 'T[keyof T]' is not assignable to type 'U[string]'. +!!! error TS2322: Type 'T[string]' is not assignable to type 'U[string]'. +!!! error TS2322: Type 'T' is not assignable to type 'U'. + ~~~~ !!! error TS2542: Index signature in type 'Readonly' only permits reading. } @@ -234,6 +253,13 @@ tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(168,5): error TS x[k] = y[k]; y[k] = x[k]; // Error ~~~~ +!!! error TS2322: Type 'T[K]' is not assignable to type 'U[K]'. +!!! error TS2322: Type 'T[string]' is not assignable to type 'U[K]'. +!!! error TS2322: Type 'T[string]' is not assignable to type 'U[string]'. +!!! error TS2322: Type 'T[K]' is not assignable to type 'U[string]'. +!!! error TS2322: Type 'T[string]' is not assignable to type 'U[string]'. +!!! error TS2322: Type 'T' is not assignable to type 'U'. + ~~~~ !!! error TS2542: Index signature in type 'Readonly' only permits reading. } diff --git a/tests/baselines/reference/objectFreeze.errors.txt b/tests/baselines/reference/objectFreeze.errors.txt index 9c28c62f534..48f41143d61 100644 --- a/tests/baselines/reference/objectFreeze.errors.txt +++ b/tests/baselines/reference/objectFreeze.errors.txt @@ -1,8 +1,9 @@ +tests/cases/compiler/objectFreeze.ts(9,1): error TS2322: Type 'string' is not assignable to type 'number'. tests/cases/compiler/objectFreeze.ts(9,1): error TS2542: Index signature in type 'ReadonlyArray' only permits reading. tests/cases/compiler/objectFreeze.ts(12,3): error TS2540: Cannot assign to 'b' because it is a constant or a read-only property. -==== tests/cases/compiler/objectFreeze.ts (2 errors) ==== +==== tests/cases/compiler/objectFreeze.ts (3 errors) ==== const f = Object.freeze(function foo(a: number, b: string) { return false; }); f(1, "") === false; @@ -13,6 +14,8 @@ tests/cases/compiler/objectFreeze.ts(12,3): error TS2540: Cannot assign to 'b' b const a = Object.freeze([1, 2, 3]); a[0] = a[2].toString(); ~~~~ +!!! error TS2322: Type 'string' is not assignable to type 'number'. + ~~~~ !!! error TS2542: Index signature in type 'ReadonlyArray' only permits reading. const o = Object.freeze({ a: 1, b: "string" }); diff --git a/tests/baselines/reference/propertyAccessOfReadonlyIndexSignature.errors.txt b/tests/baselines/reference/propertyAccessOfReadonlyIndexSignature.errors.txt new file mode 100644 index 00000000000..8fa06244162 --- /dev/null +++ b/tests/baselines/reference/propertyAccessOfReadonlyIndexSignature.errors.txt @@ -0,0 +1,13 @@ +tests/cases/compiler/propertyAccessOfReadonlyIndexSignature.ts(6,1): error TS2542: Index signature in type 'Test' only permits reading. + + +==== tests/cases/compiler/propertyAccessOfReadonlyIndexSignature.ts (1 errors) ==== + interface Test { + readonly [key: string]: string; + } + + declare var a: Test; + a.foo = 'baz'; + ~~~~~ +!!! error TS2542: Index signature in type 'Test' only permits reading. + \ No newline at end of file diff --git a/tests/baselines/reference/propertyAccessOfReadonlyIndexSignature.js b/tests/baselines/reference/propertyAccessOfReadonlyIndexSignature.js new file mode 100644 index 00000000000..a1069eca553 --- /dev/null +++ b/tests/baselines/reference/propertyAccessOfReadonlyIndexSignature.js @@ -0,0 +1,11 @@ +//// [propertyAccessOfReadonlyIndexSignature.ts] +interface Test { + readonly [key: string]: string; +} + +declare var a: Test; +a.foo = 'baz'; + + +//// [propertyAccessOfReadonlyIndexSignature.js] +a.foo = 'baz'; diff --git a/tests/cases/compiler/propertyAccessOfReadonlyIndexSignature.ts b/tests/cases/compiler/propertyAccessOfReadonlyIndexSignature.ts new file mode 100644 index 00000000000..c5f28c5b097 --- /dev/null +++ b/tests/cases/compiler/propertyAccessOfReadonlyIndexSignature.ts @@ -0,0 +1,6 @@ +interface Test { + readonly [key: string]: string; +} + +declare var a: Test; +a.foo = 'baz'; diff --git a/tests/cases/conformance/expressions/unaryOperators/decrementOperator/decrementOperatorWithEnumType.ts b/tests/cases/conformance/expressions/unaryOperators/decrementOperator/decrementOperatorWithEnumType.ts index 022ed405a0b..4caa1e1a681 100644 --- a/tests/cases/conformance/expressions/unaryOperators/decrementOperator/decrementOperatorWithEnumType.ts +++ b/tests/cases/conformance/expressions/unaryOperators/decrementOperator/decrementOperatorWithEnumType.ts @@ -9,4 +9,4 @@ var ResultIsNumber2 = ENUM1.A--; // miss assignment operator --ENUM1["A"]; -ENUM1[A]--; \ No newline at end of file +ENUM1[A]--;