diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 85700319fc371..8800aaf16f048 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -17845,7 +17845,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (indexInfo) { if (accessFlags & AccessFlags.NoIndexSignatures && indexInfo.keyType !== numberType) { if (accessExpression) { - error(accessExpression, Diagnostics.Type_0_cannot_be_used_to_index_type_1, typeToString(indexType), typeToString(originalObjectType)); + if (accessFlags & AccessFlags.Writing) { + error(accessExpression, Diagnostics.Type_0_is_generic_and_can_only_be_indexed_for_reading, typeToString(originalObjectType)); + } + else { + error(accessExpression, Diagnostics.Type_0_cannot_be_used_to_index_type_1, typeToString(indexType), typeToString(originalObjectType)); + } } return undefined; } diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 31955155b0fc9..1c102f812ebe8 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -3699,6 +3699,10 @@ "category": "Error", "code": 2861 }, + "Type '{0}' is generic and can only be indexed for reading.": { + "category": "Error", + "code": 2862 + }, "Import declaration '{0}' is using private name '{1}'.": { "category": "Error", diff --git a/tests/baselines/reference/cannotIndexGenericWritingError.errors.txt b/tests/baselines/reference/cannotIndexGenericWritingError.errors.txt new file mode 100644 index 0000000000000..7d6480a9bb051 --- /dev/null +++ b/tests/baselines/reference/cannotIndexGenericWritingError.errors.txt @@ -0,0 +1,19 @@ +cannotIndexGenericWritingError.ts(4,5): error TS2862: Type 'T' is generic and can only be indexed for reading. +cannotIndexGenericWritingError.ts(8,5): error TS2862: Type 'T' is generic and can only be indexed for reading. + + +==== cannotIndexGenericWritingError.ts (2 errors) ==== + // From #47357 + + function foo>(target: T, p: string | symbol) { + target[p] = ""; // error + ~~~~~~~~~ +!!! error TS2862: Type 'T' is generic and can only be indexed for reading. + } + + function foo2(target: T, p: string | number) { + target[p] = 1; // error + ~~~~~~~~~ +!!! error TS2862: Type 'T' is generic and can only be indexed for reading. + target[1] = 1; // ok + } \ No newline at end of file diff --git a/tests/baselines/reference/cannotIndexGenericWritingError.symbols b/tests/baselines/reference/cannotIndexGenericWritingError.symbols new file mode 100644 index 0000000000000..7ff9f6a639bcb --- /dev/null +++ b/tests/baselines/reference/cannotIndexGenericWritingError.symbols @@ -0,0 +1,33 @@ +//// [tests/cases/compiler/cannotIndexGenericWritingError.ts] //// + +=== cannotIndexGenericWritingError.ts === +// From #47357 + +function foo>(target: T, p: string | symbol) { +>foo : Symbol(foo, Decl(cannotIndexGenericWritingError.ts, 0, 0)) +>T : Symbol(T, Decl(cannotIndexGenericWritingError.ts, 2, 13)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) +>target : Symbol(target, Decl(cannotIndexGenericWritingError.ts, 2, 53)) +>T : Symbol(T, Decl(cannotIndexGenericWritingError.ts, 2, 13)) +>p : Symbol(p, Decl(cannotIndexGenericWritingError.ts, 2, 63)) + + target[p] = ""; // error +>target : Symbol(target, Decl(cannotIndexGenericWritingError.ts, 2, 53)) +>p : Symbol(p, Decl(cannotIndexGenericWritingError.ts, 2, 63)) +} + +function foo2(target: T, p: string | number) { +>foo2 : Symbol(foo2, Decl(cannotIndexGenericWritingError.ts, 4, 1)) +>T : Symbol(T, Decl(cannotIndexGenericWritingError.ts, 6, 14)) +>s : Symbol(s, Decl(cannotIndexGenericWritingError.ts, 6, 38)) +>target : Symbol(target, Decl(cannotIndexGenericWritingError.ts, 6, 69)) +>T : Symbol(T, Decl(cannotIndexGenericWritingError.ts, 6, 14)) +>p : Symbol(p, Decl(cannotIndexGenericWritingError.ts, 6, 79)) + + target[p] = 1; // error +>target : Symbol(target, Decl(cannotIndexGenericWritingError.ts, 6, 69)) +>p : Symbol(p, Decl(cannotIndexGenericWritingError.ts, 6, 79)) + + target[1] = 1; // ok +>target : Symbol(target, Decl(cannotIndexGenericWritingError.ts, 6, 69)) +} diff --git a/tests/baselines/reference/cannotIndexGenericWritingError.types b/tests/baselines/reference/cannotIndexGenericWritingError.types new file mode 100644 index 0000000000000..8701d605f6bfd --- /dev/null +++ b/tests/baselines/reference/cannotIndexGenericWritingError.types @@ -0,0 +1,38 @@ +//// [tests/cases/compiler/cannotIndexGenericWritingError.ts] //// + +=== cannotIndexGenericWritingError.ts === +// From #47357 + +function foo>(target: T, p: string | symbol) { +>foo : >(target: T, p: string | symbol) => void +>target : T +>p : string | symbol + + target[p] = ""; // error +>target[p] = "" : "" +>target[p] : any +>target : T +>p : string | symbol +>"" : "" +} + +function foo2(target: T, p: string | number) { +>foo2 : (target: T, p: string | number) => void +>s : string +>target : T +>p : string | number + + target[p] = 1; // error +>target[p] = 1 : 1 +>target[p] : any +>target : T +>p : string | number +>1 : 1 + + target[1] = 1; // ok +>target[1] = 1 : 1 +>target[1] : number +>target : T +>1 : 1 +>1 : 1 +} diff --git a/tests/baselines/reference/keyofAndIndexedAccess2.errors.txt b/tests/baselines/reference/keyofAndIndexedAccess2.errors.txt index c4e09ca02b007..472421be8dca5 100644 --- a/tests/baselines/reference/keyofAndIndexedAccess2.errors.txt +++ b/tests/baselines/reference/keyofAndIndexedAccess2.errors.txt @@ -24,7 +24,7 @@ keyofAndIndexedAccess2.ts(52,3): error TS2322: Type 'number' is not assignable t keyofAndIndexedAccess2.ts(53,3): error TS2322: Type 'number' is not assignable to type 'T[K]'. 'T[K]' could be instantiated with an arbitrary type which could be unrelated to 'number'. keyofAndIndexedAccess2.ts(65,7): error TS2339: Property 'foo' does not exist on type 'T'. -keyofAndIndexedAccess2.ts(66,3): error TS2536: Type 'string' cannot be used to index type 'T'. +keyofAndIndexedAccess2.ts(66,3): error TS2862: Type 'T' is generic and can only be indexed for reading. keyofAndIndexedAccess2.ts(67,3): error TS2322: Type 'number' is not assignable to type 'T[keyof T]'. 'number' is assignable to the constraint of type 'T[keyof T]', but 'T[keyof T]' could be instantiated with a different subtype of constraint 'number'. keyofAndIndexedAccess2.ts(68,3): error TS2322: Type 'number' is not assignable to type 'T[K]'. @@ -146,7 +146,7 @@ keyofAndIndexedAccess2.ts(108,5): error TS2322: Type '123' is not assignable to !!! error TS2339: Property 'foo' does not exist on type 'T'. obj[k1] = 123; // Error ~~~~~~~ -!!! error TS2536: Type 'string' cannot be used to index type 'T'. +!!! error TS2862: Type 'T' is generic and can only be indexed for reading. obj[k2] = 123; // Error ~~~~~~~ !!! error TS2322: Type 'number' is not assignable to type 'T[keyof T]'. diff --git a/tests/baselines/reference/mappedTypeGenericWithKnownKeys.errors.txt b/tests/baselines/reference/mappedTypeGenericWithKnownKeys.errors.txt index e5b38519c313d..3bab572ad8de9 100644 --- a/tests/baselines/reference/mappedTypeGenericWithKnownKeys.errors.txt +++ b/tests/baselines/reference/mappedTypeGenericWithKnownKeys.errors.txt @@ -1,5 +1,5 @@ mappedTypeGenericWithKnownKeys.ts(9,9): error TS2551: Property 'unknownLiteralKey' does not exist on type 'Record'. Did you mean 'knownLiteralKey'? -mappedTypeGenericWithKnownKeys.ts(10,5): error TS2536: Type 'string' cannot be used to index type 'Record'. +mappedTypeGenericWithKnownKeys.ts(10,5): error TS2862: Type 'Record' is generic and can only be indexed for reading. ==== mappedTypeGenericWithKnownKeys.ts (2 errors) ==== @@ -16,6 +16,6 @@ mappedTypeGenericWithKnownKeys.ts(10,5): error TS2536: Type 'string' cannot be u !!! error TS2551: Property 'unknownLiteralKey' does not exist on type 'Record'. Did you mean 'knownLiteralKey'? obj['' as string] = 4; // error ~~~~~~~~~~~~~~~~~ -!!! error TS2536: Type 'string' cannot be used to index type 'Record'. +!!! error TS2862: Type 'Record' is generic and can only be indexed for reading. } \ No newline at end of file diff --git a/tests/cases/compiler/cannotIndexGenericWritingError.ts b/tests/cases/compiler/cannotIndexGenericWritingError.ts new file mode 100644 index 0000000000000..7c49ee1ff5274 --- /dev/null +++ b/tests/cases/compiler/cannotIndexGenericWritingError.ts @@ -0,0 +1,13 @@ +// @strict: true +// @noEmit: true + +// From #47357 + +function foo>(target: T, p: string | symbol) { + target[p] = ""; // error +} + +function foo2(target: T, p: string | number) { + target[p] = 1; // error + target[1] = 1; // ok +} \ No newline at end of file