Skip to content

Commit 95413f0

Browse files
authored
Merge pull request #31000 from Microsoft/ignoreStringIndexSignaturesOnly
Ignore string (but keep numeric) index signatures from constraints
2 parents d865ea7 + 4ce0d20 commit 95413f0

File tree

6 files changed

+113
-5
lines changed

6 files changed

+113
-5
lines changed

src/compiler/checker.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9942,13 +9942,13 @@ namespace ts {
99429942
return type.flags & TypeFlags.Union ? getIntersectionType(map((<IntersectionType>type).types, t => getIndexType(t, stringsOnly, noIndexSignatures))) :
99439943
type.flags & TypeFlags.Intersection ? getUnionType(map((<IntersectionType>type).types, t => getIndexType(t, stringsOnly, noIndexSignatures))) :
99449944
maybeTypeOfKind(type, TypeFlags.InstantiableNonPrimitive) ? getIndexTypeForGenericType(<InstantiableType | UnionOrIntersectionType>type, stringsOnly) :
9945-
getObjectFlags(type) & ObjectFlags.Mapped ? filterType(getConstraintTypeFromMappedType(<MappedType>type), t => !(noIndexSignatures && t.flags & (TypeFlags.Any | TypeFlags.String | TypeFlags.Number))) :
9945+
getObjectFlags(type) & ObjectFlags.Mapped ? filterType(getConstraintTypeFromMappedType(<MappedType>type), t => !(noIndexSignatures && t.flags & (TypeFlags.Any | TypeFlags.String))) :
99469946
type === wildcardType ? wildcardType :
99479947
type.flags & TypeFlags.Unknown ? neverType :
99489948
type.flags & (TypeFlags.Any | TypeFlags.Never) ? keyofConstraintType :
99499949
stringsOnly ? !noIndexSignatures && getIndexInfoOfType(type, IndexKind.String) ? stringType : getLiteralTypeFromProperties(type, TypeFlags.StringLiteral) :
99509950
!noIndexSignatures && getIndexInfoOfType(type, IndexKind.String) ? getUnionType([stringType, numberType, getLiteralTypeFromProperties(type, TypeFlags.UniqueESSymbol)]) :
9951-
!noIndexSignatures && getNonEnumNumberIndexInfo(type) ? getUnionType([numberType, getLiteralTypeFromProperties(type, TypeFlags.StringLiteral | TypeFlags.UniqueESSymbol)]) :
9951+
getNonEnumNumberIndexInfo(type) ? getUnionType([numberType, getLiteralTypeFromProperties(type, TypeFlags.StringLiteral | TypeFlags.UniqueESSymbol)]) :
99529952
getLiteralTypeFromProperties(type, TypeFlags.StringOrNumberLiteralOrUnique);
99539953
}
99549954

@@ -10066,10 +10066,10 @@ namespace ts {
1006610066
if (objectType.flags & (TypeFlags.Any | TypeFlags.Never)) {
1006710067
return objectType;
1006810068
}
10069-
const indexInfo = isTypeAssignableToKind(indexType, TypeFlags.NumberLike) && getIndexInfoOfType(objectType, IndexKind.Number) ||
10070-
getIndexInfoOfType(objectType, IndexKind.String);
10069+
const stringIndexInfo = getIndexInfoOfType(objectType, IndexKind.String);
10070+
const indexInfo = isTypeAssignableToKind(indexType, TypeFlags.NumberLike) && getIndexInfoOfType(objectType, IndexKind.Number) || stringIndexInfo;
1007110071
if (indexInfo) {
10072-
if (accessFlags & AccessFlags.NoIndexSignatures) {
10072+
if (accessFlags & AccessFlags.NoIndexSignatures && indexInfo === stringIndexInfo) {
1007310073
if (accessExpression) {
1007410074
error(accessExpression, Diagnostics.Type_0_cannot_be_used_to_index_type_1, typeToString(indexType), typeToString(originalObjectType));
1007510075
}

tests/baselines/reference/keyofAndIndexedAccess2.errors.txt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,4 +194,14 @@ tests/cases/conformance/types/keyof/keyofAndIndexedAccess2.ts(108,5): error TS23
194194
type StrictExclude<T, U> = T extends StrictExtract<T, U> ? never : T;
195195
type A<T> = { [Q in { [P in keyof T]: P; }[keyof T]]: T[Q]; };
196196
type B<T, V> = A<{ [Q in keyof T]: StrictExclude<B<T[Q], V>, {}>; }>;
197+
198+
// Repros from #30938
199+
200+
function fn<T extends {elements: Array<string>} | {elements: Array<number>}>(param: T, cb: (element: T['elements'][number]) => void) {
201+
cb(param.elements[0]);
202+
}
203+
204+
function fn2<T extends Array<string>>(param: T, cb: (element: T[number]) => void) {
205+
cb(param[0]);
206+
}
197207

tests/baselines/reference/keyofAndIndexedAccess2.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,16 @@ type StrictExtract<T, U> = T extends U ? U extends T ? T : never : never;
115115
type StrictExclude<T, U> = T extends StrictExtract<T, U> ? never : T;
116116
type A<T> = { [Q in { [P in keyof T]: P; }[keyof T]]: T[Q]; };
117117
type B<T, V> = A<{ [Q in keyof T]: StrictExclude<B<T[Q], V>, {}>; }>;
118+
119+
// Repros from #30938
120+
121+
function fn<T extends {elements: Array<string>} | {elements: Array<number>}>(param: T, cb: (element: T['elements'][number]) => void) {
122+
cb(param.elements[0]);
123+
}
124+
125+
function fn2<T extends Array<string>>(param: T, cb: (element: T[number]) => void) {
126+
cb(param[0]);
127+
}
118128

119129

120130
//// [keyofAndIndexedAccess2.js]
@@ -190,3 +200,10 @@ export function getEntity(id, state) {
190200
function get123() {
191201
return 123; // Error
192202
}
203+
// Repros from #30938
204+
function fn(param, cb) {
205+
cb(param.elements[0]);
206+
}
207+
function fn2(param, cb) {
208+
cb(param[0]);
209+
}

tests/baselines/reference/keyofAndIndexedAccess2.symbols

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -434,3 +434,40 @@ type B<T, V> = A<{ [Q in keyof T]: StrictExclude<B<T[Q], V>, {}>; }>;
434434
>Q : Symbol(Q, Decl(keyofAndIndexedAccess2.ts, 115, 20))
435435
>V : Symbol(V, Decl(keyofAndIndexedAccess2.ts, 115, 9))
436436

437+
// Repros from #30938
438+
439+
function fn<T extends {elements: Array<string>} | {elements: Array<number>}>(param: T, cb: (element: T['elements'][number]) => void) {
440+
>fn : Symbol(fn, Decl(keyofAndIndexedAccess2.ts, 115, 69))
441+
>T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 119, 12))
442+
>elements : Symbol(elements, Decl(keyofAndIndexedAccess2.ts, 119, 23))
443+
>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)
444+
>elements : Symbol(elements, Decl(keyofAndIndexedAccess2.ts, 119, 51))
445+
>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)
446+
>param : Symbol(param, Decl(keyofAndIndexedAccess2.ts, 119, 77))
447+
>T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 119, 12))
448+
>cb : Symbol(cb, Decl(keyofAndIndexedAccess2.ts, 119, 86))
449+
>element : Symbol(element, Decl(keyofAndIndexedAccess2.ts, 119, 92))
450+
>T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 119, 12))
451+
452+
cb(param.elements[0]);
453+
>cb : Symbol(cb, Decl(keyofAndIndexedAccess2.ts, 119, 86))
454+
>param.elements : Symbol(elements, Decl(keyofAndIndexedAccess2.ts, 119, 23), Decl(keyofAndIndexedAccess2.ts, 119, 51))
455+
>param : Symbol(param, Decl(keyofAndIndexedAccess2.ts, 119, 77))
456+
>elements : Symbol(elements, Decl(keyofAndIndexedAccess2.ts, 119, 23), Decl(keyofAndIndexedAccess2.ts, 119, 51))
457+
}
458+
459+
function fn2<T extends Array<string>>(param: T, cb: (element: T[number]) => void) {
460+
>fn2 : Symbol(fn2, Decl(keyofAndIndexedAccess2.ts, 121, 1))
461+
>T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 123, 13))
462+
>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)
463+
>param : Symbol(param, Decl(keyofAndIndexedAccess2.ts, 123, 38))
464+
>T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 123, 13))
465+
>cb : Symbol(cb, Decl(keyofAndIndexedAccess2.ts, 123, 47))
466+
>element : Symbol(element, Decl(keyofAndIndexedAccess2.ts, 123, 53))
467+
>T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 123, 13))
468+
469+
cb(param[0]);
470+
>cb : Symbol(cb, Decl(keyofAndIndexedAccess2.ts, 123, 47))
471+
>param : Symbol(param, Decl(keyofAndIndexedAccess2.ts, 123, 38))
472+
}
473+

tests/baselines/reference/keyofAndIndexedAccess2.types

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -437,3 +437,37 @@ type A<T> = { [Q in { [P in keyof T]: P; }[keyof T]]: T[Q]; };
437437
type B<T, V> = A<{ [Q in keyof T]: StrictExclude<B<T[Q], V>, {}>; }>;
438438
>B : A<{ [Q in keyof T]: StrictExclude<A<{ [Q in keyof T[Q]]: StrictExclude<A<{ [Q in keyof T[Q][Q]]: StrictExclude<A<{ [Q in keyof T[Q][Q][Q]]: StrictExclude<A<{ [Q in keyof T[Q][Q][Q][Q]]: StrictExclude<A<{ [Q in keyof T[Q][Q][Q][Q][Q]]: StrictExclude<A<{ [Q in keyof T[Q][Q][Q][Q][Q][Q]]: StrictExclude<A<{ [Q in keyof T[Q][Q][Q][Q][Q][Q][Q]]: StrictExclude<A<{ [Q in keyof T[Q][Q][Q][Q][Q][Q][Q][Q]]: StrictExclude<A<{ [Q in keyof T[Q][Q][Q][Q][Q][Q][Q][Q][Q]]: StrictExclude<A<{ [Q in keyof T[Q][Q][Q][Q][Q][Q][Q][Q][Q][Q]]: StrictExclude<A<any>, {}>; }>, {}>; }>, {}>; }>, {}>; }>, {}>; }>, {}>; }>, {}>; }>, {}>; }>, {}>; }>, {}>; }>, {}>; }>
439439

440+
// Repros from #30938
441+
442+
function fn<T extends {elements: Array<string>} | {elements: Array<number>}>(param: T, cb: (element: T['elements'][number]) => void) {
443+
>fn : <T extends { elements: string[]; } | { elements: number[]; }>(param: T, cb: (element: T["elements"][number]) => void) => void
444+
>elements : string[]
445+
>elements : number[]
446+
>param : T
447+
>cb : (element: T["elements"][number]) => void
448+
>element : T["elements"][number]
449+
450+
cb(param.elements[0]);
451+
>cb(param.elements[0]) : void
452+
>cb : (element: T["elements"][number]) => void
453+
>param.elements[0] : string | number
454+
>param.elements : string[] | number[]
455+
>param : T
456+
>elements : string[] | number[]
457+
>0 : 0
458+
}
459+
460+
function fn2<T extends Array<string>>(param: T, cb: (element: T[number]) => void) {
461+
>fn2 : <T extends string[]>(param: T, cb: (element: T[number]) => void) => void
462+
>param : T
463+
>cb : (element: T[number]) => void
464+
>element : T[number]
465+
466+
cb(param[0]);
467+
>cb(param[0]) : void
468+
>cb : (element: T[number]) => void
469+
>param[0] : string
470+
>param : T
471+
>0 : 0
472+
}
473+

tests/cases/conformance/types/keyof/keyofAndIndexedAccess2.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,3 +117,13 @@ type StrictExtract<T, U> = T extends U ? U extends T ? T : never : never;
117117
type StrictExclude<T, U> = T extends StrictExtract<T, U> ? never : T;
118118
type A<T> = { [Q in { [P in keyof T]: P; }[keyof T]]: T[Q]; };
119119
type B<T, V> = A<{ [Q in keyof T]: StrictExclude<B<T[Q], V>, {}>; }>;
120+
121+
// Repros from #30938
122+
123+
function fn<T extends {elements: Array<string>} | {elements: Array<number>}>(param: T, cb: (element: T['elements'][number]) => void) {
124+
cb(param.elements[0]);
125+
}
126+
127+
function fn2<T extends Array<string>>(param: T, cb: (element: T[number]) => void) {
128+
cb(param[0]);
129+
}

0 commit comments

Comments
 (0)