diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 219d528f345..a08ebd1dc83 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -13436,8 +13436,9 @@ namespace ts { function getIndexTypeForMappedType(type: MappedType, noIndexSignatures: boolean | undefined) { const constraint = filterType(getConstraintTypeFromMappedType(type), t => !(noIndexSignatures && t.flags & (TypeFlags.Any | TypeFlags.String))); - return type.declaration.nameType ? - instantiateType(getTypeFromTypeNode(type.declaration.nameType), appendTypeMapping(type.mapper, getTypeParameterFromMappedType(type), constraint)) : + const nameType = type.declaration.nameType && getTypeFromTypeNode(type.declaration.nameType); + return nameType ? + mapType(constraint, t => instantiateType(nameType, appendTypeMapping(type.mapper, getTypeParameterFromMappedType(type), t))) : constraint; } diff --git a/tests/baselines/reference/mappedTypeAsClauses.js b/tests/baselines/reference/mappedTypeAsClauses.js index cefa284f1f4..9b97033306d 100644 --- a/tests/baselines/reference/mappedTypeAsClauses.js +++ b/tests/baselines/reference/mappedTypeAsClauses.js @@ -42,11 +42,30 @@ interface Person { } type LazyPerson = Lazyify; + +// Repro from #40833 + +type Example = {foo: string, bar: number}; + +type PickByValueType = { + [K in keyof T as T[K] extends U ? K : never]: T[K] +}; + +type T1 = PickByValueType; +const e1: T1 = { + foo: "hello" +}; +type T2 = keyof T1; +const e2: T2 = "foo"; //// [mappedTypeAsClauses.js] "use strict"; // Mapped type 'as N' clauses +var e1 = { + foo: "hello" +}; +var e2 = "foo"; //// [mappedTypeAsClauses.d.ts] @@ -105,3 +124,14 @@ interface Person { location?: string; } declare type LazyPerson = Lazyify; +declare type Example = { + foo: string; + bar: number; +}; +declare type PickByValueType = { + [K in keyof T as T[K] extends U ? K : never]: T[K]; +}; +declare type T1 = PickByValueType; +declare const e1: T1; +declare type T2 = keyof T1; +declare const e2: T2; diff --git a/tests/baselines/reference/mappedTypeAsClauses.symbols b/tests/baselines/reference/mappedTypeAsClauses.symbols index ec340db38c2..c37212d9658 100644 --- a/tests/baselines/reference/mappedTypeAsClauses.symbols +++ b/tests/baselines/reference/mappedTypeAsClauses.symbols @@ -143,3 +143,48 @@ type LazyPerson = Lazyify; >Lazyify : Symbol(Lazyify, Decl(mappedTypeAsClauses.ts, 28, 34)) >Person : Symbol(Person, Decl(mappedTypeAsClauses.ts, 34, 2)) +// Repro from #40833 + +type Example = {foo: string, bar: number}; +>Example : Symbol(Example, Decl(mappedTypeAsClauses.ts, 42, 34)) +>foo : Symbol(foo, Decl(mappedTypeAsClauses.ts, 46, 16)) +>bar : Symbol(bar, Decl(mappedTypeAsClauses.ts, 46, 28)) + +type PickByValueType = { +>PickByValueType : Symbol(PickByValueType, Decl(mappedTypeAsClauses.ts, 46, 42)) +>T : Symbol(T, Decl(mappedTypeAsClauses.ts, 48, 21)) +>U : Symbol(U, Decl(mappedTypeAsClauses.ts, 48, 23)) + + [K in keyof T as T[K] extends U ? K : never]: T[K] +>K : Symbol(K, Decl(mappedTypeAsClauses.ts, 49, 3)) +>T : Symbol(T, Decl(mappedTypeAsClauses.ts, 48, 21)) +>T : Symbol(T, Decl(mappedTypeAsClauses.ts, 48, 21)) +>K : Symbol(K, Decl(mappedTypeAsClauses.ts, 49, 3)) +>U : Symbol(U, Decl(mappedTypeAsClauses.ts, 48, 23)) +>K : Symbol(K, Decl(mappedTypeAsClauses.ts, 49, 3)) +>T : Symbol(T, Decl(mappedTypeAsClauses.ts, 48, 21)) +>K : Symbol(K, Decl(mappedTypeAsClauses.ts, 49, 3)) + +}; + +type T1 = PickByValueType; +>T1 : Symbol(T1, Decl(mappedTypeAsClauses.ts, 50, 2)) +>PickByValueType : Symbol(PickByValueType, Decl(mappedTypeAsClauses.ts, 46, 42)) +>Example : Symbol(Example, Decl(mappedTypeAsClauses.ts, 42, 34)) + +const e1: T1 = { +>e1 : Symbol(e1, Decl(mappedTypeAsClauses.ts, 53, 5)) +>T1 : Symbol(T1, Decl(mappedTypeAsClauses.ts, 50, 2)) + + foo: "hello" +>foo : Symbol(foo, Decl(mappedTypeAsClauses.ts, 53, 16)) + +}; +type T2 = keyof T1; +>T2 : Symbol(T2, Decl(mappedTypeAsClauses.ts, 55, 2)) +>T1 : Symbol(T1, Decl(mappedTypeAsClauses.ts, 50, 2)) + +const e2: T2 = "foo"; +>e2 : Symbol(e2, Decl(mappedTypeAsClauses.ts, 57, 5)) +>T2 : Symbol(T2, Decl(mappedTypeAsClauses.ts, 55, 2)) + diff --git a/tests/baselines/reference/mappedTypeAsClauses.types b/tests/baselines/reference/mappedTypeAsClauses.types index 1ac3ff557b1..d0a2cc5e809 100644 --- a/tests/baselines/reference/mappedTypeAsClauses.types +++ b/tests/baselines/reference/mappedTypeAsClauses.types @@ -61,7 +61,7 @@ type TD1 = DoubleProp<{ a: string, b: number }>; // { a1: string, a2: string, b >b : number type TD2 = keyof TD1; // 'a1' | 'a2' | 'b1' | 'b2' ->TD2 : "a1" | "b1" | "a2" | "b2" +>TD2 : "a1" | "a2" | "b1" | "b2" type TD3 = keyof DoubleProp; // `${keyof U & string}1` | `${keyof U & string}2` >TD3 : `${keyof U & string}1` | `${keyof U & string}2` @@ -88,3 +88,35 @@ interface Person { type LazyPerson = Lazyify; >LazyPerson : Lazyify +// Repro from #40833 + +type Example = {foo: string, bar: number}; +>Example : Example +>foo : string +>bar : number + +type PickByValueType = { +>PickByValueType : PickByValueType + + [K in keyof T as T[K] extends U ? K : never]: T[K] +}; + +type T1 = PickByValueType; +>T1 : PickByValueType + +const e1: T1 = { +>e1 : PickByValueType +>{ foo: "hello"} : { foo: string; } + + foo: "hello" +>foo : string +>"hello" : "hello" + +}; +type T2 = keyof T1; +>T2 : "foo" + +const e2: T2 = "foo"; +>e2 : "foo" +>"foo" : "foo" + diff --git a/tests/cases/conformance/types/mapped/mappedTypeAsClauses.ts b/tests/cases/conformance/types/mapped/mappedTypeAsClauses.ts index f9677a517ab..095d8ebc2cc 100644 --- a/tests/cases/conformance/types/mapped/mappedTypeAsClauses.ts +++ b/tests/cases/conformance/types/mapped/mappedTypeAsClauses.ts @@ -44,3 +44,18 @@ interface Person { } type LazyPerson = Lazyify; + +// Repro from #40833 + +type Example = {foo: string, bar: number}; + +type PickByValueType = { + [K in keyof T as T[K] extends U ? K : never]: T[K] +}; + +type T1 = PickByValueType; +const e1: T1 = { + foo: "hello" +}; +type T2 = keyof T1; +const e2: T2 = "foo";