diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index abd6fd4bf2e8d..4dd8a8fc2acac 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -31971,6 +31971,34 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } + function isReturnExpressionLiteralContext(node: Node) { + const ancestor = findAncestor(node, n => { + if (isCallOrNewExpression(n)) { + // prevent inference candidates of outer inference context to provide contextual type information for the expressions within the inner context + // that could turn fresh literal candidates in the inner context into regular types for union-like literals (such as booleans and enums) + // and that would create mismatches between inferred types for outer and inner contexts which is especially problematic when invariant type parameters are involved + // + // the call below should be ok but with the inner one receiving `boolean` as contextual type it would infer `true` for its type parameter + // and that would create outer signature applicability error with outer `Box` and inner `Box` + // + // interface Box { v: (arg: T) => T; } + // declare function invariantBox(v: T): Box + // declare function fn(arg: Box, get: () => Box): void; + // fn(invariantBox(true), () => invariantBox(true)); + return "quit"; + } + const parent = n.parent; + if (isStatement(parent)) { + return parent.kind === SyntaxKind.ReturnStatement || "quit"; + } + if (parent.kind === SyntaxKind.ArrowFunction) { + return (parent as ArrowFunction).body === n || "quit"; + } + return false; + }); + return !!(ancestor && isExpression(ancestor) && getContextualTypeForReturnExpression(ancestor, /*contextFlags*/ undefined)); + } + // If the given contextual type contains instantiable types and if a mapper representing // return type inferences is available, instantiate those types using that mapper. function instantiateContextualType(contextualType: Type | undefined, node: Node, contextFlags: ContextFlags | undefined): Type | undefined { @@ -31979,7 +32007,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // If no inferences have been made, and none of the type parameters for which we are inferring // specify default types, nothing is gained from instantiating as type parameters would just be // replaced with their constraints similar to the apparent type. - if (inferenceContext && contextFlags! & ContextFlags.Signature && some(inferenceContext.inferences, hasInferenceCandidatesOrDefault)) { + if (inferenceContext && (contextFlags! & ContextFlags.Signature || isReturnExpressionLiteralContext(node)) && some(inferenceContext.inferences, hasInferenceCandidatesOrDefault)) { // For contextual signatures we incorporate all inferences made so far, e.g. from return // types as well as arguments to the left in a function call. return instantiateInstantiableTypes(contextualType, inferenceContext.nonFixingMapper); diff --git a/tests/baselines/reference/instantiateContextualTypes2.symbols b/tests/baselines/reference/instantiateContextualTypes2.symbols new file mode 100644 index 0000000000000..a26749b566fc0 --- /dev/null +++ b/tests/baselines/reference/instantiateContextualTypes2.symbols @@ -0,0 +1,333 @@ +//// [tests/cases/compiler/instantiateContextualTypes2.ts] //// + +=== instantiateContextualTypes2.ts === +type ContextStates = +>ContextStates : Symbol(ContextStates, Decl(instantiateContextualTypes2.ts, 0, 0)) + + | { + status: "loading"; +>status : Symbol(status, Decl(instantiateContextualTypes2.ts, 1, 5)) + + data: null; +>data : Symbol(data, Decl(instantiateContextualTypes2.ts, 2, 24)) + } + | { + status: "success"; +>status : Symbol(status, Decl(instantiateContextualTypes2.ts, 5, 5)) + + data: string; +>data : Symbol(data, Decl(instantiateContextualTypes2.ts, 6, 24)) + + }; + +declare function createStore( +>createStore : Symbol(createStore, Decl(instantiateContextualTypes2.ts, 8, 6)) +>TContext : Symbol(TContext, Decl(instantiateContextualTypes2.ts, 10, 29)) + + context: TContext, +>context : Symbol(context, Decl(instantiateContextualTypes2.ts, 10, 39)) +>TContext : Symbol(TContext, Decl(instantiateContextualTypes2.ts, 10, 29)) + + config: { +>config : Symbol(config, Decl(instantiateContextualTypes2.ts, 11, 20)) + + on: Record TContext>; +>on : Symbol(on, Decl(instantiateContextualTypes2.ts, 12, 11)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) +>ctx : Symbol(ctx, Decl(instantiateContextualTypes2.ts, 13, 24)) +>TContext : Symbol(TContext, Decl(instantiateContextualTypes2.ts, 10, 29)) +>TContext : Symbol(TContext, Decl(instantiateContextualTypes2.ts, 10, 29)) + + }, +): void; + +const store1 = createStore( +>store1 : Symbol(store1, Decl(instantiateContextualTypes2.ts, 17, 5)) +>createStore : Symbol(createStore, Decl(instantiateContextualTypes2.ts, 8, 6)) + { + status: "loading", +>status : Symbol(status, Decl(instantiateContextualTypes2.ts, 18, 3)) + + data: null, +>data : Symbol(data, Decl(instantiateContextualTypes2.ts, 19, 22)) + + } as ContextStates, +>ContextStates : Symbol(ContextStates, Decl(instantiateContextualTypes2.ts, 0, 0)) + { + on: { +>on : Symbol(on, Decl(instantiateContextualTypes2.ts, 22, 3)) + + fetch: (ctx) => ({ +>fetch : Symbol(fetch, Decl(instantiateContextualTypes2.ts, 23, 9)) +>ctx : Symbol(ctx, Decl(instantiateContextualTypes2.ts, 24, 14)) + + status: "success", +>status : Symbol(status, Decl(instantiateContextualTypes2.ts, 24, 24)) + + data: "hello", +>data : Symbol(data, Decl(instantiateContextualTypes2.ts, 25, 26)) + + }), + }, + }, +); + +const store2 = createStore( +>store2 : Symbol(store2, Decl(instantiateContextualTypes2.ts, 32, 5)) +>createStore : Symbol(createStore, Decl(instantiateContextualTypes2.ts, 8, 6)) + { + status: "loading", +>status : Symbol(status, Decl(instantiateContextualTypes2.ts, 33, 3)) + + data: null, +>data : Symbol(data, Decl(instantiateContextualTypes2.ts, 34, 22)) + + } as ContextStates, +>ContextStates : Symbol(ContextStates, Decl(instantiateContextualTypes2.ts, 0, 0)) + { + on: { +>on : Symbol(on, Decl(instantiateContextualTypes2.ts, 37, 3)) + + fetch: () => ({ +>fetch : Symbol(fetch, Decl(instantiateContextualTypes2.ts, 38, 9)) + + status: "success", +>status : Symbol(status, Decl(instantiateContextualTypes2.ts, 39, 21)) + + data: "hello", +>data : Symbol(data, Decl(instantiateContextualTypes2.ts, 40, 26)) + + }), + }, + }, +); + +const store3 = createStore( +>store3 : Symbol(store3, Decl(instantiateContextualTypes2.ts, 47, 5)) +>createStore : Symbol(createStore, Decl(instantiateContextualTypes2.ts, 8, 6)) + { + status: "loading", +>status : Symbol(status, Decl(instantiateContextualTypes2.ts, 48, 3)) + + data: null, +>data : Symbol(data, Decl(instantiateContextualTypes2.ts, 49, 22)) + + } as ContextStates, +>ContextStates : Symbol(ContextStates, Decl(instantiateContextualTypes2.ts, 0, 0)) + { + on: { +>on : Symbol(on, Decl(instantiateContextualTypes2.ts, 52, 3)) + + fetch: (ctx) => { +>fetch : Symbol(fetch, Decl(instantiateContextualTypes2.ts, 53, 9)) +>ctx : Symbol(ctx, Decl(instantiateContextualTypes2.ts, 54, 14)) + + return { + status: "success", +>status : Symbol(status, Decl(instantiateContextualTypes2.ts, 55, 16)) + + data: "hello", +>data : Symbol(data, Decl(instantiateContextualTypes2.ts, 56, 28)) + + }; + }, + }, + }, +); + +const store4 = createStore( +>store4 : Symbol(store4, Decl(instantiateContextualTypes2.ts, 64, 5)) +>createStore : Symbol(createStore, Decl(instantiateContextualTypes2.ts, 8, 6)) + { + status: "loading", +>status : Symbol(status, Decl(instantiateContextualTypes2.ts, 65, 3)) + + data: null, +>data : Symbol(data, Decl(instantiateContextualTypes2.ts, 66, 22)) + + } as ContextStates, +>ContextStates : Symbol(ContextStates, Decl(instantiateContextualTypes2.ts, 0, 0)) + { + on: { +>on : Symbol(on, Decl(instantiateContextualTypes2.ts, 69, 3)) + + fetch: () => { +>fetch : Symbol(fetch, Decl(instantiateContextualTypes2.ts, 70, 9)) + + return { + status: "success", +>status : Symbol(status, Decl(instantiateContextualTypes2.ts, 72, 16)) + + data: "hello", +>data : Symbol(data, Decl(instantiateContextualTypes2.ts, 73, 28)) + + }; + }, + }, + }, +); + +declare function createStore2( +>createStore2 : Symbol(createStore2, Decl(instantiateContextualTypes2.ts, 79, 2)) +>TContext : Symbol(TContext, Decl(instantiateContextualTypes2.ts, 81, 30)) + + context: TContext, +>context : Symbol(context, Decl(instantiateContextualTypes2.ts, 81, 40)) +>TContext : Symbol(TContext, Decl(instantiateContextualTypes2.ts, 81, 30)) + + config: { +>config : Symbol(config, Decl(instantiateContextualTypes2.ts, 82, 20)) + + on: Record { context: TContext }>; +>on : Symbol(on, Decl(instantiateContextualTypes2.ts, 83, 11)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) +>ctx : Symbol(ctx, Decl(instantiateContextualTypes2.ts, 84, 24)) +>TContext : Symbol(TContext, Decl(instantiateContextualTypes2.ts, 81, 30)) +>context : Symbol(context, Decl(instantiateContextualTypes2.ts, 84, 43)) +>TContext : Symbol(TContext, Decl(instantiateContextualTypes2.ts, 81, 30)) + + }, +): void; + +const store5 = createStore2( +>store5 : Symbol(store5, Decl(instantiateContextualTypes2.ts, 88, 5)) +>createStore2 : Symbol(createStore2, Decl(instantiateContextualTypes2.ts, 79, 2)) + { + status: "loading", +>status : Symbol(status, Decl(instantiateContextualTypes2.ts, 89, 3)) + + data: null, +>data : Symbol(data, Decl(instantiateContextualTypes2.ts, 90, 22)) + + } as ContextStates, +>ContextStates : Symbol(ContextStates, Decl(instantiateContextualTypes2.ts, 0, 0)) + { + on: { +>on : Symbol(on, Decl(instantiateContextualTypes2.ts, 93, 3)) + + fetch: (ctx) => ({ +>fetch : Symbol(fetch, Decl(instantiateContextualTypes2.ts, 94, 9)) +>ctx : Symbol(ctx, Decl(instantiateContextualTypes2.ts, 95, 14)) + + context: { +>context : Symbol(context, Decl(instantiateContextualTypes2.ts, 95, 24)) + + status: "success", +>status : Symbol(status, Decl(instantiateContextualTypes2.ts, 96, 18)) + + data: "hello", +>data : Symbol(data, Decl(instantiateContextualTypes2.ts, 97, 28)) + + }, + }), + }, + }, +); + +const store6 = createStore2( +>store6 : Symbol(store6, Decl(instantiateContextualTypes2.ts, 105, 5)) +>createStore2 : Symbol(createStore2, Decl(instantiateContextualTypes2.ts, 79, 2)) + { + status: "loading", +>status : Symbol(status, Decl(instantiateContextualTypes2.ts, 106, 3)) + + data: null, +>data : Symbol(data, Decl(instantiateContextualTypes2.ts, 107, 22)) + + } as ContextStates, +>ContextStates : Symbol(ContextStates, Decl(instantiateContextualTypes2.ts, 0, 0)) + { + on: { +>on : Symbol(on, Decl(instantiateContextualTypes2.ts, 110, 3)) + + fetch: () => ({ +>fetch : Symbol(fetch, Decl(instantiateContextualTypes2.ts, 111, 9)) + + context: { +>context : Symbol(context, Decl(instantiateContextualTypes2.ts, 112, 21)) + + status: "success", +>status : Symbol(status, Decl(instantiateContextualTypes2.ts, 113, 18)) + + data: "hello", +>data : Symbol(data, Decl(instantiateContextualTypes2.ts, 114, 28)) + + }, + }), + }, + }, +); + +const store7 = createStore2( +>store7 : Symbol(store7, Decl(instantiateContextualTypes2.ts, 122, 5)) +>createStore2 : Symbol(createStore2, Decl(instantiateContextualTypes2.ts, 79, 2)) + { + status: "loading", +>status : Symbol(status, Decl(instantiateContextualTypes2.ts, 123, 3)) + + data: null, +>data : Symbol(data, Decl(instantiateContextualTypes2.ts, 124, 22)) + + } as ContextStates, +>ContextStates : Symbol(ContextStates, Decl(instantiateContextualTypes2.ts, 0, 0)) + { + on: { +>on : Symbol(on, Decl(instantiateContextualTypes2.ts, 127, 3)) + + fetch: (ctx) => { +>fetch : Symbol(fetch, Decl(instantiateContextualTypes2.ts, 128, 9)) +>ctx : Symbol(ctx, Decl(instantiateContextualTypes2.ts, 129, 14)) + + return { + context: { +>context : Symbol(context, Decl(instantiateContextualTypes2.ts, 130, 16)) + + status: "success", +>status : Symbol(status, Decl(instantiateContextualTypes2.ts, 131, 20)) + + data: "hello", +>data : Symbol(data, Decl(instantiateContextualTypes2.ts, 132, 30)) + + }, + }; + }, + }, + }, +); + +const store8 = createStore2( +>store8 : Symbol(store8, Decl(instantiateContextualTypes2.ts, 141, 5)) +>createStore2 : Symbol(createStore2, Decl(instantiateContextualTypes2.ts, 79, 2)) + { + status: "loading", +>status : Symbol(status, Decl(instantiateContextualTypes2.ts, 142, 3)) + + data: null, +>data : Symbol(data, Decl(instantiateContextualTypes2.ts, 143, 22)) + + } as ContextStates, +>ContextStates : Symbol(ContextStates, Decl(instantiateContextualTypes2.ts, 0, 0)) + { + on: { +>on : Symbol(on, Decl(instantiateContextualTypes2.ts, 146, 3)) + + fetch: () => { +>fetch : Symbol(fetch, Decl(instantiateContextualTypes2.ts, 147, 9)) + + return { + context: { +>context : Symbol(context, Decl(instantiateContextualTypes2.ts, 149, 16)) + + status: "success", +>status : Symbol(status, Decl(instantiateContextualTypes2.ts, 150, 20)) + + data: "hello", +>data : Symbol(data, Decl(instantiateContextualTypes2.ts, 151, 30)) + + }, + }; + }, + }, + }, +); + diff --git a/tests/baselines/reference/instantiateContextualTypes2.types b/tests/baselines/reference/instantiateContextualTypes2.types new file mode 100644 index 0000000000000..8d4cd4942956c --- /dev/null +++ b/tests/baselines/reference/instantiateContextualTypes2.types @@ -0,0 +1,599 @@ +//// [tests/cases/compiler/instantiateContextualTypes2.ts] //// + +=== instantiateContextualTypes2.ts === +type ContextStates = +>ContextStates : ContextStates +> : ^^^^^^^^^^^^^ + + | { + status: "loading"; +>status : "loading" +> : ^^^^^^^^^ + + data: null; +>data : null +> : ^^^^ + } + | { + status: "success"; +>status : "success" +> : ^^^^^^^^^ + + data: string; +>data : string +> : ^^^^^^ + + }; + +declare function createStore( +>createStore : (context: TContext, config: { on: Record TContext>; }) => void +> : ^ ^^ ^^ ^^ ^^ ^^^^^ + + context: TContext, +>context : TContext +> : ^^^^^^^^ + + config: { +>config : { on: Record TContext>; } +> : ^^^^^^ ^^^ + + on: Record TContext>; +>on : Record TContext> +> : ^^^^^^^^^^^^^^^^ ^^ ^^^^^ ^ +>ctx : TContext +> : ^^^^^^^^ + + }, +): void; + +const store1 = createStore( +>store1 : void +> : ^^^^ +>createStore( { status: "loading", data: null, } as ContextStates, { on: { fetch: (ctx) => ({ status: "success", data: "hello", }), }, },) : void +> : ^^^^ +>createStore : (context: TContext, config: { on: Record TContext>; }) => void +> : ^ ^^ ^^ ^^ ^^ ^^^^^ + { +>{ status: "loading", data: null, } as ContextStates : ContextStates +> : ^^^^^^^^^^^^^ +>{ status: "loading", data: null, } : { status: "loading"; data: null; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + status: "loading", +>status : "loading" +> : ^^^^^^^^^ +>"loading" : "loading" +> : ^^^^^^^^^ + + data: null, +>data : null +> : ^^^^ + + } as ContextStates, + { +>{ on: { fetch: (ctx) => ({ status: "success", data: "hello", }), }, } : { on: { fetch: (ctx: ContextStates) => { status: "success"; data: string; }; }; } +> : ^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + on: { +>on : { fetch: (ctx: ContextStates) => { status: "success"; data: string; }; } +> : ^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>{ fetch: (ctx) => ({ status: "success", data: "hello", }), } : { fetch: (ctx: ContextStates) => { status: "success"; data: string; }; } +> : ^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + fetch: (ctx) => ({ +>fetch : (ctx: ContextStates) => { status: "success"; data: string; } +> : ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>(ctx) => ({ status: "success", data: "hello", }) : (ctx: ContextStates) => { status: "success"; data: string; } +> : ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>ctx : ContextStates +> : ^^^^^^^^^^^^^ +>({ status: "success", data: "hello", }) : { status: "success"; data: string; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>{ status: "success", data: "hello", } : { status: "success"; data: string; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + status: "success", +>status : "success" +> : ^^^^^^^^^ +>"success" : "success" +> : ^^^^^^^^^ + + data: "hello", +>data : string +> : ^^^^^^ +>"hello" : "hello" +> : ^^^^^^^ + + }), + }, + }, +); + +const store2 = createStore( +>store2 : void +> : ^^^^ +>createStore( { status: "loading", data: null, } as ContextStates, { on: { fetch: () => ({ status: "success", data: "hello", }), }, },) : void +> : ^^^^ +>createStore : (context: TContext, config: { on: Record TContext>; }) => void +> : ^ ^^ ^^ ^^ ^^ ^^^^^ + { +>{ status: "loading", data: null, } as ContextStates : ContextStates +> : ^^^^^^^^^^^^^ +>{ status: "loading", data: null, } : { status: "loading"; data: null; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + status: "loading", +>status : "loading" +> : ^^^^^^^^^ +>"loading" : "loading" +> : ^^^^^^^^^ + + data: null, +>data : null +> : ^^^^ + + } as ContextStates, + { +>{ on: { fetch: () => ({ status: "success", data: "hello", }), }, } : { on: { fetch: () => { status: "success"; data: string; }; }; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + on: { +>on : { fetch: () => { status: "success"; data: string; }; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>{ fetch: () => ({ status: "success", data: "hello", }), } : { fetch: () => { status: "success"; data: string; }; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + fetch: () => ({ +>fetch : () => { status: "success"; data: string; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>() => ({ status: "success", data: "hello", }) : () => { status: "success"; data: string; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>({ status: "success", data: "hello", }) : { status: "success"; data: string; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>{ status: "success", data: "hello", } : { status: "success"; data: string; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + status: "success", +>status : "success" +> : ^^^^^^^^^ +>"success" : "success" +> : ^^^^^^^^^ + + data: "hello", +>data : string +> : ^^^^^^ +>"hello" : "hello" +> : ^^^^^^^ + + }), + }, + }, +); + +const store3 = createStore( +>store3 : void +> : ^^^^ +>createStore( { status: "loading", data: null, } as ContextStates, { on: { fetch: (ctx) => { return { status: "success", data: "hello", }; }, }, },) : void +> : ^^^^ +>createStore : (context: TContext, config: { on: Record TContext>; }) => void +> : ^ ^^ ^^ ^^ ^^ ^^^^^ + { +>{ status: "loading", data: null, } as ContextStates : ContextStates +> : ^^^^^^^^^^^^^ +>{ status: "loading", data: null, } : { status: "loading"; data: null; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + status: "loading", +>status : "loading" +> : ^^^^^^^^^ +>"loading" : "loading" +> : ^^^^^^^^^ + + data: null, +>data : null +> : ^^^^ + + } as ContextStates, + { +>{ on: { fetch: (ctx) => { return { status: "success", data: "hello", }; }, }, } : { on: { fetch: (ctx: ContextStates) => { status: "success"; data: string; }; }; } +> : ^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + on: { +>on : { fetch: (ctx: ContextStates) => { status: "success"; data: string; }; } +> : ^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>{ fetch: (ctx) => { return { status: "success", data: "hello", }; }, } : { fetch: (ctx: ContextStates) => { status: "success"; data: string; }; } +> : ^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + fetch: (ctx) => { +>fetch : (ctx: ContextStates) => { status: "success"; data: string; } +> : ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>(ctx) => { return { status: "success", data: "hello", }; } : (ctx: ContextStates) => { status: "success"; data: string; } +> : ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>ctx : ContextStates +> : ^^^^^^^^^^^^^ + + return { +>{ status: "success", data: "hello", } : { status: "success"; data: string; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + status: "success", +>status : "success" +> : ^^^^^^^^^ +>"success" : "success" +> : ^^^^^^^^^ + + data: "hello", +>data : string +> : ^^^^^^ +>"hello" : "hello" +> : ^^^^^^^ + + }; + }, + }, + }, +); + +const store4 = createStore( +>store4 : void +> : ^^^^ +>createStore( { status: "loading", data: null, } as ContextStates, { on: { fetch: () => { return { status: "success", data: "hello", }; }, }, },) : void +> : ^^^^ +>createStore : (context: TContext, config: { on: Record TContext>; }) => void +> : ^ ^^ ^^ ^^ ^^ ^^^^^ + { +>{ status: "loading", data: null, } as ContextStates : ContextStates +> : ^^^^^^^^^^^^^ +>{ status: "loading", data: null, } : { status: "loading"; data: null; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + status: "loading", +>status : "loading" +> : ^^^^^^^^^ +>"loading" : "loading" +> : ^^^^^^^^^ + + data: null, +>data : null +> : ^^^^ + + } as ContextStates, + { +>{ on: { fetch: () => { return { status: "success", data: "hello", }; }, }, } : { on: { fetch: () => { status: "success"; data: string; }; }; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + on: { +>on : { fetch: () => { status: "success"; data: string; }; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>{ fetch: () => { return { status: "success", data: "hello", }; }, } : { fetch: () => { status: "success"; data: string; }; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + fetch: () => { +>fetch : () => { status: "success"; data: string; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>() => { return { status: "success", data: "hello", }; } : () => { status: "success"; data: string; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + return { +>{ status: "success", data: "hello", } : { status: "success"; data: string; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + status: "success", +>status : "success" +> : ^^^^^^^^^ +>"success" : "success" +> : ^^^^^^^^^ + + data: "hello", +>data : string +> : ^^^^^^ +>"hello" : "hello" +> : ^^^^^^^ + + }; + }, + }, + }, +); + +declare function createStore2( +>createStore2 : (context: TContext, config: { on: Record { context: TContext; }>; }) => void +> : ^ ^^ ^^ ^^ ^^ ^^^^^ + + context: TContext, +>context : TContext +> : ^^^^^^^^ + + config: { +>config : { on: Record { context: TContext; }>; } +> : ^^^^^^ ^^^ + + on: Record { context: TContext }>; +>on : Record { context: TContext; }> +> : ^^^^^^^^^^^^^^^^ ^^ ^^^^^ ^ +>ctx : TContext +> : ^^^^^^^^ +>context : TContext +> : ^^^^^^^^ + + }, +): void; + +const store5 = createStore2( +>store5 : void +> : ^^^^ +>createStore2( { status: "loading", data: null, } as ContextStates, { on: { fetch: (ctx) => ({ context: { status: "success", data: "hello", }, }), }, },) : void +> : ^^^^ +>createStore2 : (context: TContext, config: { on: Record { context: TContext; }>; }) => void +> : ^ ^^ ^^ ^^ ^^ ^^^^^ + { +>{ status: "loading", data: null, } as ContextStates : ContextStates +> : ^^^^^^^^^^^^^ +>{ status: "loading", data: null, } : { status: "loading"; data: null; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + status: "loading", +>status : "loading" +> : ^^^^^^^^^ +>"loading" : "loading" +> : ^^^^^^^^^ + + data: null, +>data : null +> : ^^^^ + + } as ContextStates, + { +>{ on: { fetch: (ctx) => ({ context: { status: "success", data: "hello", }, }), }, } : { on: { fetch: (ctx: ContextStates) => { context: { status: "success"; data: string; }; }; }; } +> : ^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + on: { +>on : { fetch: (ctx: ContextStates) => { context: { status: "success"; data: string; }; }; } +> : ^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>{ fetch: (ctx) => ({ context: { status: "success", data: "hello", }, }), } : { fetch: (ctx: ContextStates) => { context: { status: "success"; data: string; }; }; } +> : ^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + fetch: (ctx) => ({ +>fetch : (ctx: ContextStates) => { context: { status: "success"; data: string; }; } +> : ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>(ctx) => ({ context: { status: "success", data: "hello", }, }) : (ctx: ContextStates) => { context: { status: "success"; data: string; }; } +> : ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>ctx : ContextStates +> : ^^^^^^^^^^^^^ +>({ context: { status: "success", data: "hello", }, }) : { context: { status: "success"; data: string; }; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>{ context: { status: "success", data: "hello", }, } : { context: { status: "success"; data: string; }; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + context: { +>context : { status: "success"; data: string; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>{ status: "success", data: "hello", } : { status: "success"; data: string; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + status: "success", +>status : "success" +> : ^^^^^^^^^ +>"success" : "success" +> : ^^^^^^^^^ + + data: "hello", +>data : string +> : ^^^^^^ +>"hello" : "hello" +> : ^^^^^^^ + + }, + }), + }, + }, +); + +const store6 = createStore2( +>store6 : void +> : ^^^^ +>createStore2( { status: "loading", data: null, } as ContextStates, { on: { fetch: () => ({ context: { status: "success", data: "hello", }, }), }, },) : void +> : ^^^^ +>createStore2 : (context: TContext, config: { on: Record { context: TContext; }>; }) => void +> : ^ ^^ ^^ ^^ ^^ ^^^^^ + { +>{ status: "loading", data: null, } as ContextStates : ContextStates +> : ^^^^^^^^^^^^^ +>{ status: "loading", data: null, } : { status: "loading"; data: null; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + status: "loading", +>status : "loading" +> : ^^^^^^^^^ +>"loading" : "loading" +> : ^^^^^^^^^ + + data: null, +>data : null +> : ^^^^ + + } as ContextStates, + { +>{ on: { fetch: () => ({ context: { status: "success", data: "hello", }, }), }, } : { on: { fetch: () => { context: { status: "success"; data: string; }; }; }; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + on: { +>on : { fetch: () => { context: { status: "success"; data: string; }; }; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>{ fetch: () => ({ context: { status: "success", data: "hello", }, }), } : { fetch: () => { context: { status: "success"; data: string; }; }; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + fetch: () => ({ +>fetch : () => { context: { status: "success"; data: string; }; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>() => ({ context: { status: "success", data: "hello", }, }) : () => { context: { status: "success"; data: string; }; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>({ context: { status: "success", data: "hello", }, }) : { context: { status: "success"; data: string; }; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>{ context: { status: "success", data: "hello", }, } : { context: { status: "success"; data: string; }; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + context: { +>context : { status: "success"; data: string; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>{ status: "success", data: "hello", } : { status: "success"; data: string; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + status: "success", +>status : "success" +> : ^^^^^^^^^ +>"success" : "success" +> : ^^^^^^^^^ + + data: "hello", +>data : string +> : ^^^^^^ +>"hello" : "hello" +> : ^^^^^^^ + + }, + }), + }, + }, +); + +const store7 = createStore2( +>store7 : void +> : ^^^^ +>createStore2( { status: "loading", data: null, } as ContextStates, { on: { fetch: (ctx) => { return { context: { status: "success", data: "hello", }, }; }, }, },) : void +> : ^^^^ +>createStore2 : (context: TContext, config: { on: Record { context: TContext; }>; }) => void +> : ^ ^^ ^^ ^^ ^^ ^^^^^ + { +>{ status: "loading", data: null, } as ContextStates : ContextStates +> : ^^^^^^^^^^^^^ +>{ status: "loading", data: null, } : { status: "loading"; data: null; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + status: "loading", +>status : "loading" +> : ^^^^^^^^^ +>"loading" : "loading" +> : ^^^^^^^^^ + + data: null, +>data : null +> : ^^^^ + + } as ContextStates, + { +>{ on: { fetch: (ctx) => { return { context: { status: "success", data: "hello", }, }; }, }, } : { on: { fetch: (ctx: ContextStates) => { context: { status: "success"; data: string; }; }; }; } +> : ^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + on: { +>on : { fetch: (ctx: ContextStates) => { context: { status: "success"; data: string; }; }; } +> : ^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>{ fetch: (ctx) => { return { context: { status: "success", data: "hello", }, }; }, } : { fetch: (ctx: ContextStates) => { context: { status: "success"; data: string; }; }; } +> : ^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + fetch: (ctx) => { +>fetch : (ctx: ContextStates) => { context: { status: "success"; data: string; }; } +> : ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>(ctx) => { return { context: { status: "success", data: "hello", }, }; } : (ctx: ContextStates) => { context: { status: "success"; data: string; }; } +> : ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>ctx : ContextStates +> : ^^^^^^^^^^^^^ + + return { +>{ context: { status: "success", data: "hello", }, } : { context: { status: "success"; data: string; }; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + context: { +>context : { status: "success"; data: string; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>{ status: "success", data: "hello", } : { status: "success"; data: string; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + status: "success", +>status : "success" +> : ^^^^^^^^^ +>"success" : "success" +> : ^^^^^^^^^ + + data: "hello", +>data : string +> : ^^^^^^ +>"hello" : "hello" +> : ^^^^^^^ + + }, + }; + }, + }, + }, +); + +const store8 = createStore2( +>store8 : void +> : ^^^^ +>createStore2( { status: "loading", data: null, } as ContextStates, { on: { fetch: () => { return { context: { status: "success", data: "hello", }, }; }, }, },) : void +> : ^^^^ +>createStore2 : (context: TContext, config: { on: Record { context: TContext; }>; }) => void +> : ^ ^^ ^^ ^^ ^^ ^^^^^ + { +>{ status: "loading", data: null, } as ContextStates : ContextStates +> : ^^^^^^^^^^^^^ +>{ status: "loading", data: null, } : { status: "loading"; data: null; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + status: "loading", +>status : "loading" +> : ^^^^^^^^^ +>"loading" : "loading" +> : ^^^^^^^^^ + + data: null, +>data : null +> : ^^^^ + + } as ContextStates, + { +>{ on: { fetch: () => { return { context: { status: "success", data: "hello", }, }; }, }, } : { on: { fetch: () => { context: { status: "success"; data: string; }; }; }; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + on: { +>on : { fetch: () => { context: { status: "success"; data: string; }; }; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>{ fetch: () => { return { context: { status: "success", data: "hello", }, }; }, } : { fetch: () => { context: { status: "success"; data: string; }; }; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + fetch: () => { +>fetch : () => { context: { status: "success"; data: string; }; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>() => { return { context: { status: "success", data: "hello", }, }; } : () => { context: { status: "success"; data: string; }; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + return { +>{ context: { status: "success", data: "hello", }, } : { context: { status: "success"; data: string; }; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + context: { +>context : { status: "success"; data: string; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>{ status: "success", data: "hello", } : { status: "success"; data: string; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + status: "success", +>status : "success" +> : ^^^^^^^^^ +>"success" : "success" +> : ^^^^^^^^^ + + data: "hello", +>data : string +> : ^^^^^^ +>"hello" : "hello" +> : ^^^^^^^ + + }, + }; + }, + }, + }, +); + diff --git a/tests/cases/compiler/instantiateContextualTypes2.ts b/tests/cases/compiler/instantiateContextualTypes2.ts new file mode 100644 index 0000000000000..aa5abace0b24e --- /dev/null +++ b/tests/cases/compiler/instantiateContextualTypes2.ts @@ -0,0 +1,162 @@ +// @strict: true +// @noEmit: true + +type ContextStates = + | { + status: "loading"; + data: null; + } + | { + status: "success"; + data: string; + }; + +declare function createStore( + context: TContext, + config: { + on: Record TContext>; + }, +): void; + +const store1 = createStore( + { + status: "loading", + data: null, + } as ContextStates, + { + on: { + fetch: (ctx) => ({ + status: "success", + data: "hello", + }), + }, + }, +); + +const store2 = createStore( + { + status: "loading", + data: null, + } as ContextStates, + { + on: { + fetch: () => ({ + status: "success", + data: "hello", + }), + }, + }, +); + +const store3 = createStore( + { + status: "loading", + data: null, + } as ContextStates, + { + on: { + fetch: (ctx) => { + return { + status: "success", + data: "hello", + }; + }, + }, + }, +); + +const store4 = createStore( + { + status: "loading", + data: null, + } as ContextStates, + { + on: { + fetch: () => { + return { + status: "success", + data: "hello", + }; + }, + }, + }, +); + +declare function createStore2( + context: TContext, + config: { + on: Record { context: TContext }>; + }, +): void; + +const store5 = createStore2( + { + status: "loading", + data: null, + } as ContextStates, + { + on: { + fetch: (ctx) => ({ + context: { + status: "success", + data: "hello", + }, + }), + }, + }, +); + +const store6 = createStore2( + { + status: "loading", + data: null, + } as ContextStates, + { + on: { + fetch: () => ({ + context: { + status: "success", + data: "hello", + }, + }), + }, + }, +); + +const store7 = createStore2( + { + status: "loading", + data: null, + } as ContextStates, + { + on: { + fetch: (ctx) => { + return { + context: { + status: "success", + data: "hello", + }, + }; + }, + }, + }, +); + +const store8 = createStore2( + { + status: "loading", + data: null, + } as ContextStates, + { + on: { + fetch: () => { + return { + context: { + status: "success", + data: "hello", + }, + }; + }, + }, + }, +);