Merge pull request #17710 from Microsoft/add-readonly-check-to-property-access-of-index-signature

Add readonly check to property access of index signature
This commit is contained in:
Nathan Shively-Sanders 2017-08-16 11:16:54 -07:00 committed by GitHub
commit 146f828919
9 changed files with 79 additions and 12 deletions

View file

@ -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

View file

@ -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'.
!!! error TS2304: Cannot find name 'A'.

View file

@ -10,7 +10,8 @@ var ResultIsNumber2 = ENUM1.A--;
// miss assignment operator
--ENUM1["A"];
ENUM1[A]--;
ENUM1[A]--;
//// [decrementOperatorWithEnumType.js]
// -- operator on enum type

View file

@ -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<T>' only permits reading.
tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(56,5): error TS2542: Index signature in type 'Readonly<T>' 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<U>' 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<U>' only permits reading.
tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(72,5): error TS2322: Type 'Partial<T>' is not assignable to type 'T'.
tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(78,5): error TS2322: Type 'Partial<Thing>' is not assignable to type 'Partial<T>'.
@ -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<T>(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<U>' 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<U>' only permits reading.
}

View file

@ -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<number>' 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<number>' only permits reading.
const o = Object.freeze({ a: 1, b: "string" });

View file

@ -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.

View file

@ -0,0 +1,11 @@
//// [propertyAccessOfReadonlyIndexSignature.ts]
interface Test {
readonly [key: string]: string;
}
declare var a: Test;
a.foo = 'baz';
//// [propertyAccessOfReadonlyIndexSignature.js]
a.foo = 'baz';

View file

@ -0,0 +1,6 @@
interface Test {
readonly [key: string]: string;
}
declare var a: Test;
a.foo = 'baz';

View file

@ -9,4 +9,4 @@ var ResultIsNumber2 = ENUM1.A--;
// miss assignment operator
--ENUM1["A"];
ENUM1[A]--;
ENUM1[A]--;