Skip to content

Commit ccc1613

Browse files
authored
Merge pull request microsoft#28170 from Microsoft/fixGenericMappedTypeConstraint
No constraint for { [P in K]: XXX } where K is type variable
2 parents 972c403 + 00fbded commit ccc1613

File tree

6 files changed

+104
-6
lines changed

6 files changed

+104
-6
lines changed

src/compiler/checker.ts

+3-5
Original file line numberDiff line numberDiff line change
@@ -6831,11 +6831,9 @@ namespace ts {
68316831
}
68326832
}
68336833
else {
6834-
// First, if the constraint type is a type parameter, obtain the base constraint. Then,
6835-
// if the key type is a 'keyof X', obtain 'keyof C' where C is the base constraint of X.
6836-
// Finally, iterate over the constituents of the resulting iteration type.
6837-
const keyType = constraintType.flags & TypeFlags.InstantiableNonPrimitive ? getApparentType(constraintType) : constraintType;
6838-
const iterationType = keyType.flags & TypeFlags.Index ? getIndexType(getApparentType((<IndexType>keyType).type)) : keyType;
6834+
// If the key type is a 'keyof X', obtain 'keyof C' where C is the base constraint of X.
6835+
// Then iterate over the constituents of the key type.
6836+
const iterationType = constraintType.flags & TypeFlags.Index ? getIndexType(getApparentType((<IndexType>constraintType).type)) : constraintType;
68396837
forEachType(iterationType, addMemberForKeyType);
68406838
}
68416839
setStructuredTypeMembers(type, members, emptyArray, emptyArray, stringIndexInfo, numberIndexInfo);

tests/baselines/reference/mappedTypeErrors.errors.txt

+17-1
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,11 @@ tests/cases/conformance/types/mapped/mappedTypeErrors.ts(130,39): error TS2322:
3939
tests/cases/conformance/types/mapped/mappedTypeErrors.ts(136,16): error TS2322: Type 'T' is not assignable to type 'string | number | symbol'.
4040
Type 'T' is not assignable to type 'symbol'.
4141
tests/cases/conformance/types/mapped/mappedTypeErrors.ts(136,21): error TS2536: Type 'P' cannot be used to index type 'T'.
42+
tests/cases/conformance/types/mapped/mappedTypeErrors.ts(148,17): error TS2339: Property 'foo' does not exist on type 'Pick<T, K>'.
43+
tests/cases/conformance/types/mapped/mappedTypeErrors.ts(152,17): error TS2339: Property 'foo' does not exist on type 'Record<K, number>'.
4244

4345

44-
==== tests/cases/conformance/types/mapped/mappedTypeErrors.ts (25 errors) ====
46+
==== tests/cases/conformance/types/mapped/mappedTypeErrors.ts (27 errors) ====
4547
interface Shape {
4648
name: string;
4749
width: number;
@@ -256,4 +258,18 @@ tests/cases/conformance/types/mapped/mappedTypeErrors.ts(136,21): error TS2536:
256258
pf: {x: 7},
257259
pt: {x: 7, y: false},
258260
};
261+
262+
// Repro from #28170
263+
264+
function test1<T, K extends keyof T>(obj: Pick<T, K>) {
265+
let x = obj.foo; // Error
266+
~~~
267+
!!! error TS2339: Property 'foo' does not exist on type 'Pick<T, K>'.
268+
}
269+
270+
function test2<T, K extends keyof T>(obj: Record<K, number>) {
271+
let x = obj.foo; // Error
272+
~~~
273+
!!! error TS2339: Property 'foo' does not exist on type 'Record<K, number>'.
274+
}
259275

tests/baselines/reference/mappedTypeErrors.js

+19
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,16 @@ let f: Foo2<O, 'x'> = {
142142
pf: {x: 7},
143143
pt: {x: 7, y: false},
144144
};
145+
146+
// Repro from #28170
147+
148+
function test1<T, K extends keyof T>(obj: Pick<T, K>) {
149+
let x = obj.foo; // Error
150+
}
151+
152+
function test2<T, K extends keyof T>(obj: Record<K, number>) {
153+
let x = obj.foo; // Error
154+
}
145155

146156

147157
//// [mappedTypeErrors.js]
@@ -222,6 +232,13 @@ var f = {
222232
pf: { x: 7 },
223233
pt: { x: 7, y: false }
224234
};
235+
// Repro from #28170
236+
function test1(obj) {
237+
var x = obj.foo; // Error
238+
}
239+
function test2(obj) {
240+
var x = obj.foo; // Error
241+
}
225242

226243

227244
//// [mappedTypeErrors.d.ts]
@@ -300,3 +317,5 @@ declare type O = {
300317
};
301318
declare let o: O;
302319
declare let f: Foo2<O, 'x'>;
320+
declare function test1<T, K extends keyof T>(obj: Pick<T, K>): void;
321+
declare function test2<T, K extends keyof T>(obj: Record<K, number>): void;

tests/baselines/reference/mappedTypeErrors.symbols

+31
Original file line numberDiff line numberDiff line change
@@ -540,3 +540,34 @@ let f: Foo2<O, 'x'> = {
540540

541541
};
542542

543+
// Repro from #28170
544+
545+
function test1<T, K extends keyof T>(obj: Pick<T, K>) {
546+
>test1 : Symbol(test1, Decl(mappedTypeErrors.ts, 142, 2))
547+
>T : Symbol(T, Decl(mappedTypeErrors.ts, 146, 15))
548+
>K : Symbol(K, Decl(mappedTypeErrors.ts, 146, 17))
549+
>T : Symbol(T, Decl(mappedTypeErrors.ts, 146, 15))
550+
>obj : Symbol(obj, Decl(mappedTypeErrors.ts, 146, 37))
551+
>Pick : Symbol(Pick, Decl(lib.es5.d.ts, --, --))
552+
>T : Symbol(T, Decl(mappedTypeErrors.ts, 146, 15))
553+
>K : Symbol(K, Decl(mappedTypeErrors.ts, 146, 17))
554+
555+
let x = obj.foo; // Error
556+
>x : Symbol(x, Decl(mappedTypeErrors.ts, 147, 7))
557+
>obj : Symbol(obj, Decl(mappedTypeErrors.ts, 146, 37))
558+
}
559+
560+
function test2<T, K extends keyof T>(obj: Record<K, number>) {
561+
>test2 : Symbol(test2, Decl(mappedTypeErrors.ts, 148, 1))
562+
>T : Symbol(T, Decl(mappedTypeErrors.ts, 150, 15))
563+
>K : Symbol(K, Decl(mappedTypeErrors.ts, 150, 17))
564+
>T : Symbol(T, Decl(mappedTypeErrors.ts, 150, 15))
565+
>obj : Symbol(obj, Decl(mappedTypeErrors.ts, 150, 37))
566+
>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --))
567+
>K : Symbol(K, Decl(mappedTypeErrors.ts, 150, 17))
568+
569+
let x = obj.foo; // Error
570+
>x : Symbol(x, Decl(mappedTypeErrors.ts, 151, 7))
571+
>obj : Symbol(obj, Decl(mappedTypeErrors.ts, 150, 37))
572+
}
573+

tests/baselines/reference/mappedTypeErrors.types

+24
Original file line numberDiff line numberDiff line change
@@ -501,3 +501,27 @@ let f: Foo2<O, 'x'> = {
501501

502502
};
503503

504+
// Repro from #28170
505+
506+
function test1<T, K extends keyof T>(obj: Pick<T, K>) {
507+
>test1 : <T, K extends keyof T>(obj: Pick<T, K>) => void
508+
>obj : Pick<T, K>
509+
510+
let x = obj.foo; // Error
511+
>x : any
512+
>obj.foo : any
513+
>obj : Pick<T, K>
514+
>foo : any
515+
}
516+
517+
function test2<T, K extends keyof T>(obj: Record<K, number>) {
518+
>test2 : <T, K extends keyof T>(obj: Record<K, number>) => void
519+
>obj : Record<K, number>
520+
521+
let x = obj.foo; // Error
522+
>x : any
523+
>obj.foo : any
524+
>obj : Record<K, number>
525+
>foo : any
526+
}
527+

tests/cases/conformance/types/mapped/mappedTypeErrors.ts

+10
Original file line numberDiff line numberDiff line change
@@ -144,3 +144,13 @@ let f: Foo2<O, 'x'> = {
144144
pf: {x: 7},
145145
pt: {x: 7, y: false},
146146
};
147+
148+
// Repro from #28170
149+
150+
function test1<T, K extends keyof T>(obj: Pick<T, K>) {
151+
let x = obj.foo; // Error
152+
}
153+
154+
function test2<T, K extends keyof T>(obj: Record<K, number>) {
155+
let x = obj.foo; // Error
156+
}

0 commit comments

Comments
 (0)