diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 473b41ccec5e2..c7774d2d916e7 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -9942,13 +9942,13 @@ namespace ts { return type.flags & TypeFlags.Union ? getIntersectionType(map((type).types, t => getIndexType(t, stringsOnly, noIndexSignatures))) : type.flags & TypeFlags.Intersection ? getUnionType(map((type).types, t => getIndexType(t, stringsOnly, noIndexSignatures))) : maybeTypeOfKind(type, TypeFlags.InstantiableNonPrimitive) ? getIndexTypeForGenericType(type, stringsOnly) : - getObjectFlags(type) & ObjectFlags.Mapped ? filterType(getConstraintTypeFromMappedType(type), t => !(noIndexSignatures && t.flags & (TypeFlags.Any | TypeFlags.String | TypeFlags.Number))) : + getObjectFlags(type) & ObjectFlags.Mapped ? filterType(getConstraintTypeFromMappedType(type), t => !(noIndexSignatures && t.flags & (TypeFlags.Any | TypeFlags.String))) : type === wildcardType ? wildcardType : type.flags & TypeFlags.Unknown ? neverType : type.flags & (TypeFlags.Any | TypeFlags.Never) ? keyofConstraintType : stringsOnly ? !noIndexSignatures && getIndexInfoOfType(type, IndexKind.String) ? stringType : getLiteralTypeFromProperties(type, TypeFlags.StringLiteral) : !noIndexSignatures && getIndexInfoOfType(type, IndexKind.String) ? getUnionType([stringType, numberType, getLiteralTypeFromProperties(type, TypeFlags.UniqueESSymbol)]) : - !noIndexSignatures && getNonEnumNumberIndexInfo(type) ? getUnionType([numberType, getLiteralTypeFromProperties(type, TypeFlags.StringLiteral | TypeFlags.UniqueESSymbol)]) : + getNonEnumNumberIndexInfo(type) ? getUnionType([numberType, getLiteralTypeFromProperties(type, TypeFlags.StringLiteral | TypeFlags.UniqueESSymbol)]) : getLiteralTypeFromProperties(type, TypeFlags.StringOrNumberLiteralOrUnique); } @@ -10066,10 +10066,10 @@ namespace ts { if (objectType.flags & (TypeFlags.Any | TypeFlags.Never)) { return objectType; } - const indexInfo = isTypeAssignableToKind(indexType, TypeFlags.NumberLike) && getIndexInfoOfType(objectType, IndexKind.Number) || - getIndexInfoOfType(objectType, IndexKind.String); + const stringIndexInfo = getIndexInfoOfType(objectType, IndexKind.String); + const indexInfo = isTypeAssignableToKind(indexType, TypeFlags.NumberLike) && getIndexInfoOfType(objectType, IndexKind.Number) || stringIndexInfo; if (indexInfo) { - if (accessFlags & AccessFlags.NoIndexSignatures) { + if (accessFlags & AccessFlags.NoIndexSignatures && indexInfo === stringIndexInfo) { if (accessExpression) { error(accessExpression, Diagnostics.Type_0_cannot_be_used_to_index_type_1, typeToString(indexType), typeToString(originalObjectType)); } diff --git a/tests/baselines/reference/keyofAndIndexedAccess2.errors.txt b/tests/baselines/reference/keyofAndIndexedAccess2.errors.txt index aef57c129a33d..9a937066374ab 100644 --- a/tests/baselines/reference/keyofAndIndexedAccess2.errors.txt +++ b/tests/baselines/reference/keyofAndIndexedAccess2.errors.txt @@ -194,4 +194,14 @@ tests/cases/conformance/types/keyof/keyofAndIndexedAccess2.ts(108,5): error TS23 type StrictExclude = T extends StrictExtract ? never : T; type A = { [Q in { [P in keyof T]: P; }[keyof T]]: T[Q]; }; type B = A<{ [Q in keyof T]: StrictExclude, {}>; }>; + + // Repros from #30938 + + function fn} | {elements: Array}>(param: T, cb: (element: T['elements'][number]) => void) { + cb(param.elements[0]); + } + + function fn2>(param: T, cb: (element: T[number]) => void) { + cb(param[0]); + } \ No newline at end of file diff --git a/tests/baselines/reference/keyofAndIndexedAccess2.js b/tests/baselines/reference/keyofAndIndexedAccess2.js index 1788c40563c1b..906bcd0eab3de 100644 --- a/tests/baselines/reference/keyofAndIndexedAccess2.js +++ b/tests/baselines/reference/keyofAndIndexedAccess2.js @@ -115,6 +115,16 @@ type StrictExtract = T extends U ? U extends T ? T : never : never; type StrictExclude = T extends StrictExtract ? never : T; type A = { [Q in { [P in keyof T]: P; }[keyof T]]: T[Q]; }; type B = A<{ [Q in keyof T]: StrictExclude, {}>; }>; + +// Repros from #30938 + +function fn} | {elements: Array}>(param: T, cb: (element: T['elements'][number]) => void) { + cb(param.elements[0]); +} + +function fn2>(param: T, cb: (element: T[number]) => void) { + cb(param[0]); +} //// [keyofAndIndexedAccess2.js] @@ -190,3 +200,10 @@ export function getEntity(id, state) { function get123() { return 123; // Error } +// Repros from #30938 +function fn(param, cb) { + cb(param.elements[0]); +} +function fn2(param, cb) { + cb(param[0]); +} diff --git a/tests/baselines/reference/keyofAndIndexedAccess2.symbols b/tests/baselines/reference/keyofAndIndexedAccess2.symbols index abbe38fd5c9c8..24e1a8b0674e7 100644 --- a/tests/baselines/reference/keyofAndIndexedAccess2.symbols +++ b/tests/baselines/reference/keyofAndIndexedAccess2.symbols @@ -434,3 +434,40 @@ type B = A<{ [Q in keyof T]: StrictExclude, {}>; }>; >Q : Symbol(Q, Decl(keyofAndIndexedAccess2.ts, 115, 20)) >V : Symbol(V, Decl(keyofAndIndexedAccess2.ts, 115, 9)) +// Repros from #30938 + +function fn} | {elements: Array}>(param: T, cb: (element: T['elements'][number]) => void) { +>fn : Symbol(fn, Decl(keyofAndIndexedAccess2.ts, 115, 69)) +>T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 119, 12)) +>elements : Symbol(elements, Decl(keyofAndIndexedAccess2.ts, 119, 23)) +>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --) ... and 2 more) +>elements : Symbol(elements, Decl(keyofAndIndexedAccess2.ts, 119, 51)) +>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --) ... and 2 more) +>param : Symbol(param, Decl(keyofAndIndexedAccess2.ts, 119, 77)) +>T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 119, 12)) +>cb : Symbol(cb, Decl(keyofAndIndexedAccess2.ts, 119, 86)) +>element : Symbol(element, Decl(keyofAndIndexedAccess2.ts, 119, 92)) +>T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 119, 12)) + + cb(param.elements[0]); +>cb : Symbol(cb, Decl(keyofAndIndexedAccess2.ts, 119, 86)) +>param.elements : Symbol(elements, Decl(keyofAndIndexedAccess2.ts, 119, 23), Decl(keyofAndIndexedAccess2.ts, 119, 51)) +>param : Symbol(param, Decl(keyofAndIndexedAccess2.ts, 119, 77)) +>elements : Symbol(elements, Decl(keyofAndIndexedAccess2.ts, 119, 23), Decl(keyofAndIndexedAccess2.ts, 119, 51)) +} + +function fn2>(param: T, cb: (element: T[number]) => void) { +>fn2 : Symbol(fn2, Decl(keyofAndIndexedAccess2.ts, 121, 1)) +>T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 123, 13)) +>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --) ... and 2 more) +>param : Symbol(param, Decl(keyofAndIndexedAccess2.ts, 123, 38)) +>T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 123, 13)) +>cb : Symbol(cb, Decl(keyofAndIndexedAccess2.ts, 123, 47)) +>element : Symbol(element, Decl(keyofAndIndexedAccess2.ts, 123, 53)) +>T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 123, 13)) + + cb(param[0]); +>cb : Symbol(cb, Decl(keyofAndIndexedAccess2.ts, 123, 47)) +>param : Symbol(param, Decl(keyofAndIndexedAccess2.ts, 123, 38)) +} + diff --git a/tests/baselines/reference/keyofAndIndexedAccess2.types b/tests/baselines/reference/keyofAndIndexedAccess2.types index 4eccf23a80430..6c0f3dff934d8 100644 --- a/tests/baselines/reference/keyofAndIndexedAccess2.types +++ b/tests/baselines/reference/keyofAndIndexedAccess2.types @@ -437,3 +437,37 @@ type A = { [Q in { [P in keyof T]: P; }[keyof T]]: T[Q]; }; type B = A<{ [Q in keyof T]: StrictExclude, {}>; }>; >B : A<{ [Q in keyof T]: StrictExclude, {}>; }>, {}>; }>, {}>; }>, {}>; }>, {}>; }>, {}>; }>, {}>; }>, {}>; }>, {}>; }>, {}>; }>, {}>; }> +// Repros from #30938 + +function fn} | {elements: Array}>(param: T, cb: (element: T['elements'][number]) => void) { +>fn : (param: T, cb: (element: T["elements"][number]) => void) => void +>elements : string[] +>elements : number[] +>param : T +>cb : (element: T["elements"][number]) => void +>element : T["elements"][number] + + cb(param.elements[0]); +>cb(param.elements[0]) : void +>cb : (element: T["elements"][number]) => void +>param.elements[0] : string | number +>param.elements : string[] | number[] +>param : T +>elements : string[] | number[] +>0 : 0 +} + +function fn2>(param: T, cb: (element: T[number]) => void) { +>fn2 : (param: T, cb: (element: T[number]) => void) => void +>param : T +>cb : (element: T[number]) => void +>element : T[number] + + cb(param[0]); +>cb(param[0]) : void +>cb : (element: T[number]) => void +>param[0] : string +>param : T +>0 : 0 +} + diff --git a/tests/cases/conformance/types/keyof/keyofAndIndexedAccess2.ts b/tests/cases/conformance/types/keyof/keyofAndIndexedAccess2.ts index 26daf35ee50c4..356e0a42ae9b4 100644 --- a/tests/cases/conformance/types/keyof/keyofAndIndexedAccess2.ts +++ b/tests/cases/conformance/types/keyof/keyofAndIndexedAccess2.ts @@ -117,3 +117,13 @@ type StrictExtract = T extends U ? U extends T ? T : never : never; type StrictExclude = T extends StrictExtract ? never : T; type A = { [Q in { [P in keyof T]: P; }[keyof T]]: T[Q]; }; type B = A<{ [Q in keyof T]: StrictExclude, {}>; }>; + +// Repros from #30938 + +function fn} | {elements: Array}>(param: T, cb: (element: T['elements'][number]) => void) { + cb(param.elements[0]); +} + +function fn2>(param: T, cb: (element: T[number]) => void) { + cb(param[0]); +}