From 1889b93948efbaa028890ac70be8102ca2f66041 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Thu, 4 Jan 2024 23:03:39 +0100 Subject: [PATCH 1/2] Improve contextual typing when the `returnMapper` is involved --- src/compiler/checker.ts | 8 +- .../contextualTypeInNestedInference1.symbols | 105 ++++++++++++++++++ .../contextualTypeInNestedInference1.types | 94 ++++++++++++++++ ...inferFromGenericFunctionReturnTypes3.types | 6 +- .../contextualTypeInNestedInference1.ts | 38 +++++++ 5 files changed, 247 insertions(+), 4 deletions(-) create mode 100644 tests/baselines/reference/contextualTypeInNestedInference1.symbols create mode 100644 tests/baselines/reference/contextualTypeInNestedInference1.types create mode 100644 tests/cases/compiler/contextualTypeInNestedInference1.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 7fcd96913ae06..0a027c15a72ea 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -30619,9 +30619,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // the 'boolean' type from the contextual type such that contextually typed boolean // literals actually end up widening to 'boolean' (see #48363). const type = instantiateInstantiableTypes(contextualType, inferenceContext.returnMapper); + // nothing is gained from contextual 'never' type so the uninstantiated type is kept + if (type.flags & TypeFlags.Never) { + return contextualType; + } return type.flags & TypeFlags.Union && containsType((type as UnionType).types, regularFalseType) && containsType((type as UnionType).types, regularTrueType) ? filterType(type, t => t !== regularFalseType && t !== regularTrueType) : - type; + // intersecting helps to avoid widening when contextual type is a type parameter constrained to a primitive + // and when the instantiated by the returnMapper type is that primitive type + getIntersectionType([contextualType, type]); } } return contextualType; diff --git a/tests/baselines/reference/contextualTypeInNestedInference1.symbols b/tests/baselines/reference/contextualTypeInNestedInference1.symbols new file mode 100644 index 0000000000000..4057b54346ae8 --- /dev/null +++ b/tests/baselines/reference/contextualTypeInNestedInference1.symbols @@ -0,0 +1,105 @@ +//// [tests/cases/compiler/contextualTypeInNestedInference1.ts] //// + +=== contextualTypeInNestedInference1.ts === +// https://github.com/microsoft/TypeScript/issues/56912 + +interface NameBag = {}> { +>NameBag : Symbol(NameBag, Decl(contextualTypeInNestedInference1.ts, 0, 0)) +>Names : Symbol(Names, Decl(contextualTypeInNestedInference1.ts, 2, 18)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) + + addName(options: { +>addName : Symbol(NameBag.addName, Decl(contextualTypeInNestedInference1.ts, 2, 59)) +>Name : Symbol(Name, Decl(contextualTypeInNestedInference1.ts, 3, 10)) +>options : Symbol(options, Decl(contextualTypeInNestedInference1.ts, 3, 31)) + + name: Name; +>name : Symbol(name, Decl(contextualTypeInNestedInference1.ts, 3, 41)) +>Name : Symbol(Name, Decl(contextualTypeInNestedInference1.ts, 3, 10)) + + }): NameBag< +>NameBag : Symbol(NameBag, Decl(contextualTypeInNestedInference1.ts, 0, 0)) + + Names & { +>Names : Symbol(Names, Decl(contextualTypeInNestedInference1.ts, 2, 18)) + + [key in Name]: { name: true }; +>key : Symbol(key, Decl(contextualTypeInNestedInference1.ts, 7, 7)) +>Name : Symbol(Name, Decl(contextualTypeInNestedInference1.ts, 3, 10)) +>name : Symbol(name, Decl(contextualTypeInNestedInference1.ts, 7, 22)) + } + >; +} + +const emptyBag: NameBag = null as any; +>emptyBag : Symbol(emptyBag, Decl(contextualTypeInNestedInference1.ts, 12, 5)) +>NameBag : Symbol(NameBag, Decl(contextualTypeInNestedInference1.ts, 0, 0)) + +const standalone = emptyBag.addName({ name: "hey!" }); +>standalone : Symbol(standalone, Decl(contextualTypeInNestedInference1.ts, 14, 5)) +>emptyBag.addName : Symbol(NameBag.addName, Decl(contextualTypeInNestedInference1.ts, 2, 59)) +>emptyBag : Symbol(emptyBag, Decl(contextualTypeInNestedInference1.ts, 12, 5)) +>addName : Symbol(NameBag.addName, Decl(contextualTypeInNestedInference1.ts, 2, 59)) +>name : Symbol(name, Decl(contextualTypeInNestedInference1.ts, 14, 37)) + +function wrapper1>( +>wrapper1 : Symbol(wrapper1, Decl(contextualTypeInNestedInference1.ts, 14, 54)) +>Schema : Symbol(Schema, Decl(contextualTypeInNestedInference1.ts, 16, 18)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) +>NameBag : Symbol(NameBag, Decl(contextualTypeInNestedInference1.ts, 0, 0)) + + schema: Schema, +>schema : Symbol(schema, Decl(contextualTypeInNestedInference1.ts, 16, 58)) +>Schema : Symbol(Schema, Decl(contextualTypeInNestedInference1.ts, 16, 18)) + +): Schema { +>Schema : Symbol(Schema, Decl(contextualTypeInNestedInference1.ts, 16, 18)) + + return schema; +>schema : Symbol(schema, Decl(contextualTypeInNestedInference1.ts, 16, 58)) +} + +const bagOfBags1 = wrapper1({ +>bagOfBags1 : Symbol(bagOfBags1, Decl(contextualTypeInNestedInference1.ts, 22, 5)) +>wrapper1 : Symbol(wrapper1, Decl(contextualTypeInNestedInference1.ts, 14, 54)) + + prop: emptyBag.addName({ name: "hey!" }), +>prop : Symbol(prop, Decl(contextualTypeInNestedInference1.ts, 22, 29)) +>emptyBag.addName : Symbol(NameBag.addName, Decl(contextualTypeInNestedInference1.ts, 2, 59)) +>emptyBag : Symbol(emptyBag, Decl(contextualTypeInNestedInference1.ts, 12, 5)) +>addName : Symbol(NameBag.addName, Decl(contextualTypeInNestedInference1.ts, 2, 59)) +>name : Symbol(name, Decl(contextualTypeInNestedInference1.ts, 23, 26)) + +}); + +function wrapper2>>>( +>wrapper2 : Symbol(wrapper2, Decl(contextualTypeInNestedInference1.ts, 24, 3)) +>Schema : Symbol(Schema, Decl(contextualTypeInNestedInference1.ts, 26, 18)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) +>NameBag : Symbol(NameBag, Decl(contextualTypeInNestedInference1.ts, 0, 0)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) + + schema: Schema, +>schema : Symbol(schema, Decl(contextualTypeInNestedInference1.ts, 26, 79)) +>Schema : Symbol(Schema, Decl(contextualTypeInNestedInference1.ts, 26, 18)) + +): Schema { +>Schema : Symbol(Schema, Decl(contextualTypeInNestedInference1.ts, 26, 18)) + + return schema; +>schema : Symbol(schema, Decl(contextualTypeInNestedInference1.ts, 26, 79)) +} + +const bagOfBags2 = wrapper2({ +>bagOfBags2 : Symbol(bagOfBags2, Decl(contextualTypeInNestedInference1.ts, 32, 5)) +>wrapper2 : Symbol(wrapper2, Decl(contextualTypeInNestedInference1.ts, 24, 3)) + + prop: emptyBag.addName({ name: "hey!" }), +>prop : Symbol(prop, Decl(contextualTypeInNestedInference1.ts, 32, 29)) +>emptyBag.addName : Symbol(NameBag.addName, Decl(contextualTypeInNestedInference1.ts, 2, 59)) +>emptyBag : Symbol(emptyBag, Decl(contextualTypeInNestedInference1.ts, 12, 5)) +>addName : Symbol(NameBag.addName, Decl(contextualTypeInNestedInference1.ts, 2, 59)) +>name : Symbol(name, Decl(contextualTypeInNestedInference1.ts, 33, 26)) + +}); + diff --git a/tests/baselines/reference/contextualTypeInNestedInference1.types b/tests/baselines/reference/contextualTypeInNestedInference1.types new file mode 100644 index 0000000000000..7b74c53d29bf3 --- /dev/null +++ b/tests/baselines/reference/contextualTypeInNestedInference1.types @@ -0,0 +1,94 @@ +//// [tests/cases/compiler/contextualTypeInNestedInference1.ts] //// + +=== contextualTypeInNestedInference1.ts === +// https://github.com/microsoft/TypeScript/issues/56912 + +interface NameBag = {}> { + addName(options: { +>addName : (options: { name: Name;}) => NameBag +>options : { name: Name; } + + name: Name; +>name : Name + + }): NameBag< + Names & { + [key in Name]: { name: true }; +>name : true +>true : true + } + >; +} + +const emptyBag: NameBag = null as any; +>emptyBag : NameBag<{}> +>null as any : any + +const standalone = emptyBag.addName({ name: "hey!" }); +>standalone : NameBag<{ "hey!": { name: true; }; }> +>emptyBag.addName({ name: "hey!" }) : NameBag<{ "hey!": { name: true; }; }> +>emptyBag.addName : (options: { name: Name; }) => NameBag<{ [key in Name]: { name: true; }; }> +>emptyBag : NameBag<{}> +>addName : (options: { name: Name; }) => NameBag<{ [key in Name]: { name: true; }; }> +>{ name: "hey!" } : { name: "hey!"; } +>name : "hey!" +>"hey!" : "hey!" + +function wrapper1>( +>wrapper1 : >>(schema: Schema) => Schema + + schema: Schema, +>schema : Schema + +): Schema { + return schema; +>schema : Schema +} + +const bagOfBags1 = wrapper1({ +>bagOfBags1 : { prop: NameBag<{ "hey!": { name: true; }; }>; } +>wrapper1({ prop: emptyBag.addName({ name: "hey!" }),}) : { prop: NameBag<{ "hey!": { name: true; }; }>; } +>wrapper1 : >>(schema: Schema) => Schema +>{ prop: emptyBag.addName({ name: "hey!" }),} : { prop: NameBag<{ "hey!": { name: true; }; }>; } + + prop: emptyBag.addName({ name: "hey!" }), +>prop : NameBag<{ "hey!": { name: true; }; }> +>emptyBag.addName({ name: "hey!" }) : NameBag<{ "hey!": { name: true; }; }> +>emptyBag.addName : (options: { name: Name; }) => NameBag<{ [key in Name]: { name: true; }; }> +>emptyBag : NameBag<{}> +>addName : (options: { name: Name; }) => NameBag<{ [key in Name]: { name: true; }; }> +>{ name: "hey!" } : { name: "hey!"; } +>name : "hey!" +>"hey!" : "hey!" + +}); + +function wrapper2>>>( +>wrapper2 : >>>(schema: Schema) => Schema + + schema: Schema, +>schema : Schema + +): Schema { + return schema; +>schema : Schema +} + +const bagOfBags2 = wrapper2({ +>bagOfBags2 : { prop: NameBag<{ "hey!": { name: true; }; }>; } +>wrapper2({ prop: emptyBag.addName({ name: "hey!" }),}) : { prop: NameBag<{ "hey!": { name: true; }; }>; } +>wrapper2 : >>>(schema: Schema) => Schema +>{ prop: emptyBag.addName({ name: "hey!" }),} : { prop: NameBag<{ "hey!": { name: true; }; }>; } + + prop: emptyBag.addName({ name: "hey!" }), +>prop : NameBag<{ "hey!": { name: true; }; }> +>emptyBag.addName({ name: "hey!" }) : NameBag<{ "hey!": { name: true; }; }> +>emptyBag.addName : (options: { name: Name; }) => NameBag<{ [key in Name]: { name: true; }; }> +>emptyBag : NameBag<{}> +>addName : (options: { name: Name; }) => NameBag<{ [key in Name]: { name: true; }; }> +>{ name: "hey!" } : { name: "hey!"; } +>name : "hey!" +>"hey!" : "hey!" + +}); + diff --git a/tests/baselines/reference/inferFromGenericFunctionReturnTypes3.types b/tests/baselines/reference/inferFromGenericFunctionReturnTypes3.types index 7d001af103620..7ceea2a15e2a1 100644 --- a/tests/baselines/reference/inferFromGenericFunctionReturnTypes3.types +++ b/tests/baselines/reference/inferFromGenericFunctionReturnTypes3.types @@ -411,14 +411,14 @@ type F = () => Promise>; const f1: F = () => { >f1 : F ->() => { return Promise.all([ { name: "David Gomes", age: 23, position: "GOALKEEPER", }, { name: "Cristiano Ronaldo", age: 33, position: "STRIKER", } ]);} : () => Promise<({ name: string; age: number; position: "GOALKEEPER"; } | { name: string; age: number; position: "STRIKER"; })[]> +>() => { return Promise.all([ { name: "David Gomes", age: 23, position: "GOALKEEPER", }, { name: "Cristiano Ronaldo", age: 33, position: "STRIKER", } ]);} : () => Promise<[{ name: string; age: number; position: "GOALKEEPER"; }, { name: string; age: number; position: "STRIKER"; }]> return Promise.all([ ->Promise.all([ { name: "David Gomes", age: 23, position: "GOALKEEPER", }, { name: "Cristiano Ronaldo", age: 33, position: "STRIKER", } ]) : Promise<({ name: string; age: number; position: "GOALKEEPER"; } | { name: string; age: number; position: "STRIKER"; })[]> +>Promise.all([ { name: "David Gomes", age: 23, position: "GOALKEEPER", }, { name: "Cristiano Ronaldo", age: 33, position: "STRIKER", } ]) : Promise<[{ name: string; age: number; position: "GOALKEEPER"; }, { name: string; age: number; position: "STRIKER"; }]> >Promise.all : { (values: Iterable>): Promise[]>; (values: T_1): Promise<{ -readonly [P in keyof T_1]: Awaited; }>; } >Promise : PromiseConstructor >all : { (values: Iterable>): Promise[]>; (values: T_1): Promise<{ -readonly [P in keyof T_1]: Awaited; }>; } ->[ { name: "David Gomes", age: 23, position: "GOALKEEPER", }, { name: "Cristiano Ronaldo", age: 33, position: "STRIKER", } ] : ({ name: string; age: number; position: "GOALKEEPER"; } | { name: string; age: number; position: "STRIKER"; })[] +>[ { name: "David Gomes", age: 23, position: "GOALKEEPER", }, { name: "Cristiano Ronaldo", age: 33, position: "STRIKER", } ] : [{ name: string; age: number; position: "GOALKEEPER"; }, { name: string; age: number; position: "STRIKER"; }] { >{ name: "David Gomes", age: 23, position: "GOALKEEPER", } : { name: string; age: number; position: "GOALKEEPER"; } diff --git a/tests/cases/compiler/contextualTypeInNestedInference1.ts b/tests/cases/compiler/contextualTypeInNestedInference1.ts new file mode 100644 index 0000000000000..c83758741c0db --- /dev/null +++ b/tests/cases/compiler/contextualTypeInNestedInference1.ts @@ -0,0 +1,38 @@ +// @strict: true +// @noEmit: true + +// https://github.com/microsoft/TypeScript/issues/56912 + +interface NameBag = {}> { + addName(options: { + name: Name; + }): NameBag< + Names & { + [key in Name]: { name: true }; + } + >; +} + +const emptyBag: NameBag = null as any; + +const standalone = emptyBag.addName({ name: "hey!" }); + +function wrapper1>( + schema: Schema, +): Schema { + return schema; +} + +const bagOfBags1 = wrapper1({ + prop: emptyBag.addName({ name: "hey!" }), +}); + +function wrapper2>>>( + schema: Schema, +): Schema { + return schema; +} + +const bagOfBags2 = wrapper2({ + prop: emptyBag.addName({ name: "hey!" }), +}); From 163b34fb27fa6bf33bb0d4fd99a71c67e3137d59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Mon, 12 Feb 2024 12:41:16 +0100 Subject: [PATCH 2/2] add an extra test case --- ...estedInference2(strictnullchecks=false).js | 23 ++++++++ ...Inference2(strictnullchecks=false).symbols | 53 +++++++++++++++++++ ...edInference2(strictnullchecks=false).types | 53 +++++++++++++++++++ ...NestedInference2(strictnullchecks=true).js | 23 ++++++++ ...dInference2(strictnullchecks=true).symbols | 53 +++++++++++++++++++ ...tedInference2(strictnullchecks=true).types | 53 +++++++++++++++++++ .../contextualTypeInNestedInference2.ts | 14 +++++ 7 files changed, 272 insertions(+) create mode 100644 tests/baselines/reference/contextualTypeInNestedInference2(strictnullchecks=false).js create mode 100644 tests/baselines/reference/contextualTypeInNestedInference2(strictnullchecks=false).symbols create mode 100644 tests/baselines/reference/contextualTypeInNestedInference2(strictnullchecks=false).types create mode 100644 tests/baselines/reference/contextualTypeInNestedInference2(strictnullchecks=true).js create mode 100644 tests/baselines/reference/contextualTypeInNestedInference2(strictnullchecks=true).symbols create mode 100644 tests/baselines/reference/contextualTypeInNestedInference2(strictnullchecks=true).types create mode 100644 tests/cases/compiler/contextualTypeInNestedInference2.ts diff --git a/tests/baselines/reference/contextualTypeInNestedInference2(strictnullchecks=false).js b/tests/baselines/reference/contextualTypeInNestedInference2(strictnullchecks=false).js new file mode 100644 index 0000000000000..18351d792899e --- /dev/null +++ b/tests/baselines/reference/contextualTypeInNestedInference2(strictnullchecks=false).js @@ -0,0 +1,23 @@ +//// [tests/cases/compiler/contextualTypeInNestedInference2.ts] //// + +//// [contextualTypeInNestedInference2.ts] +// https://github.com/microsoft/TypeScript/issues/50787 + +type Model = { s: string; b: boolean } +declare let pick: (properties: readonly Keys[]) => Pick +declare let transform1: (obj: T) => T +declare let transform2: (obj: T) => T + +const result1 = transform1(pick(["s"])) +const result2 = transform2(pick(["s"])) + +const intermediate = pick(["s"]) +const result3 = transform1(intermediate) + + +//// [contextualTypeInNestedInference2.js] +// https://github.com/microsoft/TypeScript/issues/50787 +var result1 = transform1(pick(["s"])); +var result2 = transform2(pick(["s"])); +var intermediate = pick(["s"]); +var result3 = transform1(intermediate); diff --git a/tests/baselines/reference/contextualTypeInNestedInference2(strictnullchecks=false).symbols b/tests/baselines/reference/contextualTypeInNestedInference2(strictnullchecks=false).symbols new file mode 100644 index 0000000000000..6fdd69349cffb --- /dev/null +++ b/tests/baselines/reference/contextualTypeInNestedInference2(strictnullchecks=false).symbols @@ -0,0 +1,53 @@ +//// [tests/cases/compiler/contextualTypeInNestedInference2.ts] //// + +=== contextualTypeInNestedInference2.ts === +// https://github.com/microsoft/TypeScript/issues/50787 + +type Model = { s: string; b: boolean } +>Model : Symbol(Model, Decl(contextualTypeInNestedInference2.ts, 0, 0)) +>s : Symbol(s, Decl(contextualTypeInNestedInference2.ts, 2, 14)) +>b : Symbol(b, Decl(contextualTypeInNestedInference2.ts, 2, 25)) + +declare let pick: (properties: readonly Keys[]) => Pick +>pick : Symbol(pick, Decl(contextualTypeInNestedInference2.ts, 3, 11)) +>Keys : Symbol(Keys, Decl(contextualTypeInNestedInference2.ts, 3, 19)) +>Model : Symbol(Model, Decl(contextualTypeInNestedInference2.ts, 0, 0)) +>properties : Symbol(properties, Decl(contextualTypeInNestedInference2.ts, 3, 45)) +>Keys : Symbol(Keys, Decl(contextualTypeInNestedInference2.ts, 3, 19)) +>Pick : Symbol(Pick, Decl(lib.es5.d.ts, --, --)) +>Model : Symbol(Model, Decl(contextualTypeInNestedInference2.ts, 0, 0)) +>Keys : Symbol(Keys, Decl(contextualTypeInNestedInference2.ts, 3, 19)) + +declare let transform1: (obj: T) => T +>transform1 : Symbol(transform1, Decl(contextualTypeInNestedInference2.ts, 4, 11)) +>T : Symbol(T, Decl(contextualTypeInNestedInference2.ts, 4, 25)) +>obj : Symbol(obj, Decl(contextualTypeInNestedInference2.ts, 4, 28)) +>T : Symbol(T, Decl(contextualTypeInNestedInference2.ts, 4, 25)) +>T : Symbol(T, Decl(contextualTypeInNestedInference2.ts, 4, 25)) + +declare let transform2: (obj: T) => T +>transform2 : Symbol(transform2, Decl(contextualTypeInNestedInference2.ts, 5, 11)) +>T : Symbol(T, Decl(contextualTypeInNestedInference2.ts, 5, 25)) +>obj : Symbol(obj, Decl(contextualTypeInNestedInference2.ts, 5, 39)) +>T : Symbol(T, Decl(contextualTypeInNestedInference2.ts, 5, 25)) +>T : Symbol(T, Decl(contextualTypeInNestedInference2.ts, 5, 25)) + +const result1 = transform1(pick(["s"])) +>result1 : Symbol(result1, Decl(contextualTypeInNestedInference2.ts, 7, 5)) +>transform1 : Symbol(transform1, Decl(contextualTypeInNestedInference2.ts, 4, 11)) +>pick : Symbol(pick, Decl(contextualTypeInNestedInference2.ts, 3, 11)) + +const result2 = transform2(pick(["s"])) +>result2 : Symbol(result2, Decl(contextualTypeInNestedInference2.ts, 8, 5)) +>transform2 : Symbol(transform2, Decl(contextualTypeInNestedInference2.ts, 5, 11)) +>pick : Symbol(pick, Decl(contextualTypeInNestedInference2.ts, 3, 11)) + +const intermediate = pick(["s"]) +>intermediate : Symbol(intermediate, Decl(contextualTypeInNestedInference2.ts, 10, 5)) +>pick : Symbol(pick, Decl(contextualTypeInNestedInference2.ts, 3, 11)) + +const result3 = transform1(intermediate) +>result3 : Symbol(result3, Decl(contextualTypeInNestedInference2.ts, 11, 5)) +>transform1 : Symbol(transform1, Decl(contextualTypeInNestedInference2.ts, 4, 11)) +>intermediate : Symbol(intermediate, Decl(contextualTypeInNestedInference2.ts, 10, 5)) + diff --git a/tests/baselines/reference/contextualTypeInNestedInference2(strictnullchecks=false).types b/tests/baselines/reference/contextualTypeInNestedInference2(strictnullchecks=false).types new file mode 100644 index 0000000000000..e136f5943098c --- /dev/null +++ b/tests/baselines/reference/contextualTypeInNestedInference2(strictnullchecks=false).types @@ -0,0 +1,53 @@ +//// [tests/cases/compiler/contextualTypeInNestedInference2.ts] //// + +=== contextualTypeInNestedInference2.ts === +// https://github.com/microsoft/TypeScript/issues/50787 + +type Model = { s: string; b: boolean } +>Model : { s: string; b: boolean; } +>s : string +>b : boolean + +declare let pick: (properties: readonly Keys[]) => Pick +>pick : (properties: readonly Keys[]) => Pick +>properties : readonly Keys[] + +declare let transform1: (obj: T) => T +>transform1 : (obj: T) => T +>obj : T + +declare let transform2: (obj: T) => T +>transform2 : (obj: T) => T +>obj : T + +const result1 = transform1(pick(["s"])) +>result1 : Pick +>transform1(pick(["s"])) : Pick +>transform1 : (obj: T) => T +>pick(["s"]) : Pick +>pick : (properties: readonly Keys[]) => Pick +>["s"] : "s"[] +>"s" : "s" + +const result2 = transform2(pick(["s"])) +>result2 : Pick +>transform2(pick(["s"])) : Pick +>transform2 : (obj: T) => T +>pick(["s"]) : Pick +>pick : (properties: readonly Keys[]) => Pick +>["s"] : "s"[] +>"s" : "s" + +const intermediate = pick(["s"]) +>intermediate : Pick +>pick(["s"]) : Pick +>pick : (properties: readonly Keys[]) => Pick +>["s"] : "s"[] +>"s" : "s" + +const result3 = transform1(intermediate) +>result3 : Pick +>transform1(intermediate) : Pick +>transform1 : (obj: T) => T +>intermediate : Pick + diff --git a/tests/baselines/reference/contextualTypeInNestedInference2(strictnullchecks=true).js b/tests/baselines/reference/contextualTypeInNestedInference2(strictnullchecks=true).js new file mode 100644 index 0000000000000..18351d792899e --- /dev/null +++ b/tests/baselines/reference/contextualTypeInNestedInference2(strictnullchecks=true).js @@ -0,0 +1,23 @@ +//// [tests/cases/compiler/contextualTypeInNestedInference2.ts] //// + +//// [contextualTypeInNestedInference2.ts] +// https://github.com/microsoft/TypeScript/issues/50787 + +type Model = { s: string; b: boolean } +declare let pick: (properties: readonly Keys[]) => Pick +declare let transform1: (obj: T) => T +declare let transform2: (obj: T) => T + +const result1 = transform1(pick(["s"])) +const result2 = transform2(pick(["s"])) + +const intermediate = pick(["s"]) +const result3 = transform1(intermediate) + + +//// [contextualTypeInNestedInference2.js] +// https://github.com/microsoft/TypeScript/issues/50787 +var result1 = transform1(pick(["s"])); +var result2 = transform2(pick(["s"])); +var intermediate = pick(["s"]); +var result3 = transform1(intermediate); diff --git a/tests/baselines/reference/contextualTypeInNestedInference2(strictnullchecks=true).symbols b/tests/baselines/reference/contextualTypeInNestedInference2(strictnullchecks=true).symbols new file mode 100644 index 0000000000000..6fdd69349cffb --- /dev/null +++ b/tests/baselines/reference/contextualTypeInNestedInference2(strictnullchecks=true).symbols @@ -0,0 +1,53 @@ +//// [tests/cases/compiler/contextualTypeInNestedInference2.ts] //// + +=== contextualTypeInNestedInference2.ts === +// https://github.com/microsoft/TypeScript/issues/50787 + +type Model = { s: string; b: boolean } +>Model : Symbol(Model, Decl(contextualTypeInNestedInference2.ts, 0, 0)) +>s : Symbol(s, Decl(contextualTypeInNestedInference2.ts, 2, 14)) +>b : Symbol(b, Decl(contextualTypeInNestedInference2.ts, 2, 25)) + +declare let pick: (properties: readonly Keys[]) => Pick +>pick : Symbol(pick, Decl(contextualTypeInNestedInference2.ts, 3, 11)) +>Keys : Symbol(Keys, Decl(contextualTypeInNestedInference2.ts, 3, 19)) +>Model : Symbol(Model, Decl(contextualTypeInNestedInference2.ts, 0, 0)) +>properties : Symbol(properties, Decl(contextualTypeInNestedInference2.ts, 3, 45)) +>Keys : Symbol(Keys, Decl(contextualTypeInNestedInference2.ts, 3, 19)) +>Pick : Symbol(Pick, Decl(lib.es5.d.ts, --, --)) +>Model : Symbol(Model, Decl(contextualTypeInNestedInference2.ts, 0, 0)) +>Keys : Symbol(Keys, Decl(contextualTypeInNestedInference2.ts, 3, 19)) + +declare let transform1: (obj: T) => T +>transform1 : Symbol(transform1, Decl(contextualTypeInNestedInference2.ts, 4, 11)) +>T : Symbol(T, Decl(contextualTypeInNestedInference2.ts, 4, 25)) +>obj : Symbol(obj, Decl(contextualTypeInNestedInference2.ts, 4, 28)) +>T : Symbol(T, Decl(contextualTypeInNestedInference2.ts, 4, 25)) +>T : Symbol(T, Decl(contextualTypeInNestedInference2.ts, 4, 25)) + +declare let transform2: (obj: T) => T +>transform2 : Symbol(transform2, Decl(contextualTypeInNestedInference2.ts, 5, 11)) +>T : Symbol(T, Decl(contextualTypeInNestedInference2.ts, 5, 25)) +>obj : Symbol(obj, Decl(contextualTypeInNestedInference2.ts, 5, 39)) +>T : Symbol(T, Decl(contextualTypeInNestedInference2.ts, 5, 25)) +>T : Symbol(T, Decl(contextualTypeInNestedInference2.ts, 5, 25)) + +const result1 = transform1(pick(["s"])) +>result1 : Symbol(result1, Decl(contextualTypeInNestedInference2.ts, 7, 5)) +>transform1 : Symbol(transform1, Decl(contextualTypeInNestedInference2.ts, 4, 11)) +>pick : Symbol(pick, Decl(contextualTypeInNestedInference2.ts, 3, 11)) + +const result2 = transform2(pick(["s"])) +>result2 : Symbol(result2, Decl(contextualTypeInNestedInference2.ts, 8, 5)) +>transform2 : Symbol(transform2, Decl(contextualTypeInNestedInference2.ts, 5, 11)) +>pick : Symbol(pick, Decl(contextualTypeInNestedInference2.ts, 3, 11)) + +const intermediate = pick(["s"]) +>intermediate : Symbol(intermediate, Decl(contextualTypeInNestedInference2.ts, 10, 5)) +>pick : Symbol(pick, Decl(contextualTypeInNestedInference2.ts, 3, 11)) + +const result3 = transform1(intermediate) +>result3 : Symbol(result3, Decl(contextualTypeInNestedInference2.ts, 11, 5)) +>transform1 : Symbol(transform1, Decl(contextualTypeInNestedInference2.ts, 4, 11)) +>intermediate : Symbol(intermediate, Decl(contextualTypeInNestedInference2.ts, 10, 5)) + diff --git a/tests/baselines/reference/contextualTypeInNestedInference2(strictnullchecks=true).types b/tests/baselines/reference/contextualTypeInNestedInference2(strictnullchecks=true).types new file mode 100644 index 0000000000000..e136f5943098c --- /dev/null +++ b/tests/baselines/reference/contextualTypeInNestedInference2(strictnullchecks=true).types @@ -0,0 +1,53 @@ +//// [tests/cases/compiler/contextualTypeInNestedInference2.ts] //// + +=== contextualTypeInNestedInference2.ts === +// https://github.com/microsoft/TypeScript/issues/50787 + +type Model = { s: string; b: boolean } +>Model : { s: string; b: boolean; } +>s : string +>b : boolean + +declare let pick: (properties: readonly Keys[]) => Pick +>pick : (properties: readonly Keys[]) => Pick +>properties : readonly Keys[] + +declare let transform1: (obj: T) => T +>transform1 : (obj: T) => T +>obj : T + +declare let transform2: (obj: T) => T +>transform2 : (obj: T) => T +>obj : T + +const result1 = transform1(pick(["s"])) +>result1 : Pick +>transform1(pick(["s"])) : Pick +>transform1 : (obj: T) => T +>pick(["s"]) : Pick +>pick : (properties: readonly Keys[]) => Pick +>["s"] : "s"[] +>"s" : "s" + +const result2 = transform2(pick(["s"])) +>result2 : Pick +>transform2(pick(["s"])) : Pick +>transform2 : (obj: T) => T +>pick(["s"]) : Pick +>pick : (properties: readonly Keys[]) => Pick +>["s"] : "s"[] +>"s" : "s" + +const intermediate = pick(["s"]) +>intermediate : Pick +>pick(["s"]) : Pick +>pick : (properties: readonly Keys[]) => Pick +>["s"] : "s"[] +>"s" : "s" + +const result3 = transform1(intermediate) +>result3 : Pick +>transform1(intermediate) : Pick +>transform1 : (obj: T) => T +>intermediate : Pick + diff --git a/tests/cases/compiler/contextualTypeInNestedInference2.ts b/tests/cases/compiler/contextualTypeInNestedInference2.ts new file mode 100644 index 0000000000000..4217d676e9e35 --- /dev/null +++ b/tests/cases/compiler/contextualTypeInNestedInference2.ts @@ -0,0 +1,14 @@ +// @strictNullChecks: true, false + +// https://github.com/microsoft/TypeScript/issues/50787 + +type Model = { s: string; b: boolean } +declare let pick: (properties: readonly Keys[]) => Pick +declare let transform1: (obj: T) => T +declare let transform2: (obj: T) => T + +const result1 = transform1(pick(["s"])) +const result2 = transform2(pick(["s"])) + +const intermediate = pick(["s"]) +const result3 = transform1(intermediate)