Skip to content

Commit 4538e73

Browse files
authored
Properly distribute over unions in keyof for mapped types with as clause (microsoft#40837)
* Properly distribute over unions in keyof mapped types with as clause * Accept new baselines * Add regression test * Accept new baselines
1 parent 3511123 commit 4538e73

File tree

5 files changed

+126
-3
lines changed

5 files changed

+126
-3
lines changed

src/compiler/checker.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13436,8 +13436,9 @@ namespace ts {
1343613436

1343713437
function getIndexTypeForMappedType(type: MappedType, noIndexSignatures: boolean | undefined) {
1343813438
const constraint = filterType(getConstraintTypeFromMappedType(type), t => !(noIndexSignatures && t.flags & (TypeFlags.Any | TypeFlags.String)));
13439-
return type.declaration.nameType ?
13440-
instantiateType(getTypeFromTypeNode(type.declaration.nameType), appendTypeMapping(type.mapper, getTypeParameterFromMappedType(type), constraint)) :
13439+
const nameType = type.declaration.nameType && getTypeFromTypeNode(type.declaration.nameType);
13440+
return nameType ?
13441+
mapType(constraint, t => instantiateType(nameType, appendTypeMapping(type.mapper, getTypeParameterFromMappedType(type), t))) :
1344113442
constraint;
1344213443
}
1344313444

tests/baselines/reference/mappedTypeAsClauses.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,30 @@ interface Person {
4242
}
4343
4444
type LazyPerson = Lazyify<Person>;
45+
46+
// Repro from #40833
47+
48+
type Example = {foo: string, bar: number};
49+
50+
type PickByValueType<T, U> = {
51+
[K in keyof T as T[K] extends U ? K : never]: T[K]
52+
};
53+
54+
type T1 = PickByValueType<Example, string>;
55+
const e1: T1 = {
56+
foo: "hello"
57+
};
58+
type T2 = keyof T1;
59+
const e2: T2 = "foo";
4560
4661
4762
//// [mappedTypeAsClauses.js]
4863
"use strict";
4964
// Mapped type 'as N' clauses
65+
var e1 = {
66+
foo: "hello"
67+
};
68+
var e2 = "foo";
5069
5170
5271
//// [mappedTypeAsClauses.d.ts]
@@ -105,3 +124,14 @@ interface Person {
105124
location?: string;
106125
}
107126
declare type LazyPerson = Lazyify<Person>;
127+
declare type Example = {
128+
foo: string;
129+
bar: number;
130+
};
131+
declare type PickByValueType<T, U> = {
132+
[K in keyof T as T[K] extends U ? K : never]: T[K];
133+
};
134+
declare type T1 = PickByValueType<Example, string>;
135+
declare const e1: T1;
136+
declare type T2 = keyof T1;
137+
declare const e2: T2;

tests/baselines/reference/mappedTypeAsClauses.symbols

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,3 +143,48 @@ type LazyPerson = Lazyify<Person>;
143143
>Lazyify : Symbol(Lazyify, Decl(mappedTypeAsClauses.ts, 28, 34))
144144
>Person : Symbol(Person, Decl(mappedTypeAsClauses.ts, 34, 2))
145145

146+
// Repro from #40833
147+
148+
type Example = {foo: string, bar: number};
149+
>Example : Symbol(Example, Decl(mappedTypeAsClauses.ts, 42, 34))
150+
>foo : Symbol(foo, Decl(mappedTypeAsClauses.ts, 46, 16))
151+
>bar : Symbol(bar, Decl(mappedTypeAsClauses.ts, 46, 28))
152+
153+
type PickByValueType<T, U> = {
154+
>PickByValueType : Symbol(PickByValueType, Decl(mappedTypeAsClauses.ts, 46, 42))
155+
>T : Symbol(T, Decl(mappedTypeAsClauses.ts, 48, 21))
156+
>U : Symbol(U, Decl(mappedTypeAsClauses.ts, 48, 23))
157+
158+
[K in keyof T as T[K] extends U ? K : never]: T[K]
159+
>K : Symbol(K, Decl(mappedTypeAsClauses.ts, 49, 3))
160+
>T : Symbol(T, Decl(mappedTypeAsClauses.ts, 48, 21))
161+
>T : Symbol(T, Decl(mappedTypeAsClauses.ts, 48, 21))
162+
>K : Symbol(K, Decl(mappedTypeAsClauses.ts, 49, 3))
163+
>U : Symbol(U, Decl(mappedTypeAsClauses.ts, 48, 23))
164+
>K : Symbol(K, Decl(mappedTypeAsClauses.ts, 49, 3))
165+
>T : Symbol(T, Decl(mappedTypeAsClauses.ts, 48, 21))
166+
>K : Symbol(K, Decl(mappedTypeAsClauses.ts, 49, 3))
167+
168+
};
169+
170+
type T1 = PickByValueType<Example, string>;
171+
>T1 : Symbol(T1, Decl(mappedTypeAsClauses.ts, 50, 2))
172+
>PickByValueType : Symbol(PickByValueType, Decl(mappedTypeAsClauses.ts, 46, 42))
173+
>Example : Symbol(Example, Decl(mappedTypeAsClauses.ts, 42, 34))
174+
175+
const e1: T1 = {
176+
>e1 : Symbol(e1, Decl(mappedTypeAsClauses.ts, 53, 5))
177+
>T1 : Symbol(T1, Decl(mappedTypeAsClauses.ts, 50, 2))
178+
179+
foo: "hello"
180+
>foo : Symbol(foo, Decl(mappedTypeAsClauses.ts, 53, 16))
181+
182+
};
183+
type T2 = keyof T1;
184+
>T2 : Symbol(T2, Decl(mappedTypeAsClauses.ts, 55, 2))
185+
>T1 : Symbol(T1, Decl(mappedTypeAsClauses.ts, 50, 2))
186+
187+
const e2: T2 = "foo";
188+
>e2 : Symbol(e2, Decl(mappedTypeAsClauses.ts, 57, 5))
189+
>T2 : Symbol(T2, Decl(mappedTypeAsClauses.ts, 55, 2))
190+

tests/baselines/reference/mappedTypeAsClauses.types

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ type TD1 = DoubleProp<{ a: string, b: number }>; // { a1: string, a2: string, b
6161
>b : number
6262

6363
type TD2 = keyof TD1; // 'a1' | 'a2' | 'b1' | 'b2'
64-
>TD2 : "a1" | "b1" | "a2" | "b2"
64+
>TD2 : "a1" | "a2" | "b1" | "b2"
6565

6666
type TD3<U> = keyof DoubleProp<U>; // `${keyof U & string}1` | `${keyof U & string}2`
6767
>TD3 : `${keyof U & string}1` | `${keyof U & string}2`
@@ -88,3 +88,35 @@ interface Person {
8888
type LazyPerson = Lazyify<Person>;
8989
>LazyPerson : Lazyify<Person>
9090

91+
// Repro from #40833
92+
93+
type Example = {foo: string, bar: number};
94+
>Example : Example
95+
>foo : string
96+
>bar : number
97+
98+
type PickByValueType<T, U> = {
99+
>PickByValueType : PickByValueType<T, U>
100+
101+
[K in keyof T as T[K] extends U ? K : never]: T[K]
102+
};
103+
104+
type T1 = PickByValueType<Example, string>;
105+
>T1 : PickByValueType<Example, string>
106+
107+
const e1: T1 = {
108+
>e1 : PickByValueType<Example, string>
109+
>{ foo: "hello"} : { foo: string; }
110+
111+
foo: "hello"
112+
>foo : string
113+
>"hello" : "hello"
114+
115+
};
116+
type T2 = keyof T1;
117+
>T2 : "foo"
118+
119+
const e2: T2 = "foo";
120+
>e2 : "foo"
121+
>"foo" : "foo"
122+

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

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,3 +44,18 @@ interface Person {
4444
}
4545

4646
type LazyPerson = Lazyify<Person>;
47+
48+
// Repro from #40833
49+
50+
type Example = {foo: string, bar: number};
51+
52+
type PickByValueType<T, U> = {
53+
[K in keyof T as T[K] extends U ? K : never]: T[K]
54+
};
55+
56+
type T1 = PickByValueType<Example, string>;
57+
const e1: T1 = {
58+
foo: "hello"
59+
};
60+
type T2 = keyof T1;
61+
const e2: T2 = "foo";

0 commit comments

Comments
 (0)