Improve error message for index signature on generic type when writing (#55906)

This commit is contained in:
Gabriela Araujo Britto 2023-10-18 17:43:43 -07:00 committed by GitHub
parent 413179867f
commit b1f5ef69e8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 117 additions and 5 deletions

View File

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

View File

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

View File

@ -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<T extends Record<string | symbol, any>>(target: T, p: string | symbol) {
target[p] = ""; // error
~~~~~~~~~
!!! error TS2862: Type 'T' is generic and can only be indexed for reading.
}
function foo2<T extends number[] & { [s: string]: number | string }>(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
}

View File

@ -0,0 +1,33 @@
//// [tests/cases/compiler/cannotIndexGenericWritingError.ts] ////
=== cannotIndexGenericWritingError.ts ===
// From #47357
function foo<T extends Record<string | symbol, any>>(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<T extends number[] & { [s: string]: number | string }>(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))
}

View File

@ -0,0 +1,38 @@
//// [tests/cases/compiler/cannotIndexGenericWritingError.ts] ////
=== cannotIndexGenericWritingError.ts ===
// From #47357
function foo<T extends Record<string | symbol, any>>(target: T, p: string | symbol) {
>foo : <T extends Record<string | symbol, any>>(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<T extends number[] & { [s: string]: number | string }>(target: T, p: string | number) {
>foo2 : <T extends number[] & { [s: string]: string | number; }>(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
}

View File

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

View File

@ -1,5 +1,5 @@
mappedTypeGenericWithKnownKeys.ts(9,9): error TS2551: Property 'unknownLiteralKey' does not exist on type 'Record<keyof Shape | "knownLiteralKey", number>'. Did you mean 'knownLiteralKey'?
mappedTypeGenericWithKnownKeys.ts(10,5): error TS2536: Type 'string' cannot be used to index type 'Record<keyof Shape | "knownLiteralKey", number>'.
mappedTypeGenericWithKnownKeys.ts(10,5): error TS2862: Type 'Record<keyof Shape | "knownLiteralKey", number>' 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<keyof Shape | "knownLiteralKey", number>'. Did you mean 'knownLiteralKey'?
obj['' as string] = 4; // error
~~~~~~~~~~~~~~~~~
!!! error TS2536: Type 'string' cannot be used to index type 'Record<keyof Shape | "knownLiteralKey", number>'.
!!! error TS2862: Type 'Record<keyof Shape | "knownLiteralKey", number>' is generic and can only be indexed for reading.
}

View File

@ -0,0 +1,13 @@
// @strict: true
// @noEmit: true
// From #47357
function foo<T extends Record<string | symbol, any>>(target: T, p: string | symbol) {
target[p] = ""; // error
}
function foo2<T extends number[] & { [s: string]: number | string }>(target: T, p: string | number) {
target[p] = 1; // error
target[1] = 1; // ok
}