diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index dfd479127202c..42067e3d7e2ae 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -40002,7 +40002,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (type.flags & TypeFlags.UnionOrIntersection) { const types = (type as UnionOrIntersectionType).types; for (const t of types) { - if (maybeTypeOfKind(t, kind)) { + if (maybeTypeOfKind(isNoInferType(t) ? (t as SubstitutionType).baseType : t, kind)) { return true; } } diff --git a/tests/baselines/reference/noInferIntersectedWithEmptyObjectKeyof1.symbols b/tests/baselines/reference/noInferIntersectedWithEmptyObjectKeyof1.symbols new file mode 100644 index 0000000000000..497afdf04c86d --- /dev/null +++ b/tests/baselines/reference/noInferIntersectedWithEmptyObjectKeyof1.symbols @@ -0,0 +1,151 @@ +//// [tests/cases/conformance/types/typeRelationships/typeInference/noInferIntersectedWithEmptyObjectKeyof1.ts] //// + +=== noInferIntersectedWithEmptyObjectKeyof1.ts === +// https://github.com/microsoft/TypeScript/issues/61091 + +type Keys = keyof (NoInfer<{ foo: string }> & {}); // "foo" +>Keys : Symbol(Keys, Decl(noInferIntersectedWithEmptyObjectKeyof1.ts, 0, 0)) +>NoInfer : Symbol(NoInfer, Decl(lib.es5.d.ts, --, --)) +>foo : Symbol(foo, Decl(noInferIntersectedWithEmptyObjectKeyof1.ts, 2, 28)) + +type LowInfer = T & {}; +>LowInfer : Symbol(LowInfer, Decl(noInferIntersectedWithEmptyObjectKeyof1.ts, 2, 50)) +>T : Symbol(T, Decl(noInferIntersectedWithEmptyObjectKeyof1.ts, 4, 14)) +>T : Symbol(T, Decl(noInferIntersectedWithEmptyObjectKeyof1.ts, 4, 14)) + +type PropertyAssigner = { +>PropertyAssigner : Symbol(PropertyAssigner, Decl(noInferIntersectedWithEmptyObjectKeyof1.ts, 4, 26)) +>TContext : Symbol(TContext, Decl(noInferIntersectedWithEmptyObjectKeyof1.ts, 5, 22)) + + [K in keyof TContext]?: (context: TContext) => TContext[K]; +>K : Symbol(K, Decl(noInferIntersectedWithEmptyObjectKeyof1.ts, 6, 3)) +>TContext : Symbol(TContext, Decl(noInferIntersectedWithEmptyObjectKeyof1.ts, 5, 22)) +>context : Symbol(context, Decl(noInferIntersectedWithEmptyObjectKeyof1.ts, 6, 27)) +>TContext : Symbol(TContext, Decl(noInferIntersectedWithEmptyObjectKeyof1.ts, 5, 22)) +>TContext : Symbol(TContext, Decl(noInferIntersectedWithEmptyObjectKeyof1.ts, 5, 22)) +>K : Symbol(K, Decl(noInferIntersectedWithEmptyObjectKeyof1.ts, 6, 3)) + +}; +type Source = { +>Source : Symbol(Source, Decl(noInferIntersectedWithEmptyObjectKeyof1.ts, 7, 2)) + + count: () => number; +>count : Symbol(count, Decl(noInferIntersectedWithEmptyObjectKeyof1.ts, 8, 15)) + +}; +type Target = PropertyAssigner>>; +>Target : Symbol(Target, Decl(noInferIntersectedWithEmptyObjectKeyof1.ts, 10, 2)) +>PropertyAssigner : Symbol(PropertyAssigner, Decl(noInferIntersectedWithEmptyObjectKeyof1.ts, 4, 26)) +>LowInfer : Symbol(LowInfer, Decl(noInferIntersectedWithEmptyObjectKeyof1.ts, 2, 50)) +>NoInfer : Symbol(NoInfer, Decl(lib.es5.d.ts, --, --)) +>count : Symbol(count, Decl(noInferIntersectedWithEmptyObjectKeyof1.ts, 11, 49)) + +declare const source: Source; +>source : Symbol(source, Decl(noInferIntersectedWithEmptyObjectKeyof1.ts, 12, 13)) +>Source : Symbol(Source, Decl(noInferIntersectedWithEmptyObjectKeyof1.ts, 7, 2)) + +const target: Target = source; // ok +>target : Symbol(target, Decl(noInferIntersectedWithEmptyObjectKeyof1.ts, 13, 5)) +>Target : Symbol(Target, Decl(noInferIntersectedWithEmptyObjectKeyof1.ts, 10, 2)) +>source : Symbol(source, Decl(noInferIntersectedWithEmptyObjectKeyof1.ts, 12, 13)) + +type ActionFunction = { +>ActionFunction : Symbol(ActionFunction, Decl(noInferIntersectedWithEmptyObjectKeyof1.ts, 13, 30)) +>TContext : Symbol(TContext, Decl(noInferIntersectedWithEmptyObjectKeyof1.ts, 15, 20)) + + (args: { context: TContext }): void; +>args : Symbol(args, Decl(noInferIntersectedWithEmptyObjectKeyof1.ts, 16, 3)) +>context : Symbol(context, Decl(noInferIntersectedWithEmptyObjectKeyof1.ts, 16, 10)) +>TContext : Symbol(TContext, Decl(noInferIntersectedWithEmptyObjectKeyof1.ts, 15, 20)) + + _out_TContext?: TContext; +>_out_TContext : Symbol(_out_TContext, Decl(noInferIntersectedWithEmptyObjectKeyof1.ts, 16, 38)) +>TContext : Symbol(TContext, Decl(noInferIntersectedWithEmptyObjectKeyof1.ts, 15, 20)) + +}; + +type TransitionsConfig = Record< +>TransitionsConfig : Symbol(TransitionsConfig, Decl(noInferIntersectedWithEmptyObjectKeyof1.ts, 18, 2)) +>TContext : Symbol(TContext, Decl(noInferIntersectedWithEmptyObjectKeyof1.ts, 20, 23)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) + + string, + { + actions?: ActionFunction; +>actions : Symbol(actions, Decl(noInferIntersectedWithEmptyObjectKeyof1.ts, 22, 3)) +>ActionFunction : Symbol(ActionFunction, Decl(noInferIntersectedWithEmptyObjectKeyof1.ts, 13, 30)) +>TContext : Symbol(TContext, Decl(noInferIntersectedWithEmptyObjectKeyof1.ts, 20, 23)) + } +>; + +declare function assign( +>assign : Symbol(assign, Decl(noInferIntersectedWithEmptyObjectKeyof1.ts, 25, 2)) +>TContext : Symbol(TContext, Decl(noInferIntersectedWithEmptyObjectKeyof1.ts, 27, 24)) + + assignment: PropertyAssigner>, +>assignment : Symbol(assignment, Decl(noInferIntersectedWithEmptyObjectKeyof1.ts, 27, 34)) +>PropertyAssigner : Symbol(PropertyAssigner, Decl(noInferIntersectedWithEmptyObjectKeyof1.ts, 4, 26)) +>LowInfer : Symbol(LowInfer, Decl(noInferIntersectedWithEmptyObjectKeyof1.ts, 2, 50)) +>TContext : Symbol(TContext, Decl(noInferIntersectedWithEmptyObjectKeyof1.ts, 27, 24)) + +): ActionFunction; +>ActionFunction : Symbol(ActionFunction, Decl(noInferIntersectedWithEmptyObjectKeyof1.ts, 13, 30)) +>TContext : Symbol(TContext, Decl(noInferIntersectedWithEmptyObjectKeyof1.ts, 27, 24)) + +declare function createMachine(config: { +>createMachine : Symbol(createMachine, Decl(noInferIntersectedWithEmptyObjectKeyof1.ts, 29, 28)) +>TContext : Symbol(TContext, Decl(noInferIntersectedWithEmptyObjectKeyof1.ts, 31, 31)) +>config : Symbol(config, Decl(noInferIntersectedWithEmptyObjectKeyof1.ts, 31, 41)) + + types?: { +>types : Symbol(types, Decl(noInferIntersectedWithEmptyObjectKeyof1.ts, 31, 50)) + + context?: TContext; +>context : Symbol(context, Decl(noInferIntersectedWithEmptyObjectKeyof1.ts, 32, 11)) +>TContext : Symbol(TContext, Decl(noInferIntersectedWithEmptyObjectKeyof1.ts, 31, 31)) + + }; + on?: TransitionsConfig>; +>on : Symbol(on, Decl(noInferIntersectedWithEmptyObjectKeyof1.ts, 34, 4)) +>TransitionsConfig : Symbol(TransitionsConfig, Decl(noInferIntersectedWithEmptyObjectKeyof1.ts, 18, 2)) +>NoInfer : Symbol(NoInfer, Decl(lib.es5.d.ts, --, --)) +>TContext : Symbol(TContext, Decl(noInferIntersectedWithEmptyObjectKeyof1.ts, 31, 31)) + +}): void; + +createMachine({ +>createMachine : Symbol(createMachine, Decl(noInferIntersectedWithEmptyObjectKeyof1.ts, 29, 28)) + + types: { +>types : Symbol(types, Decl(noInferIntersectedWithEmptyObjectKeyof1.ts, 38, 15)) + + context: { +>context : Symbol(context, Decl(noInferIntersectedWithEmptyObjectKeyof1.ts, 39, 10)) + + count: 0, +>count : Symbol(count, Decl(noInferIntersectedWithEmptyObjectKeyof1.ts, 40, 14)) + + }, + }, + on: { +>on : Symbol(on, Decl(noInferIntersectedWithEmptyObjectKeyof1.ts, 43, 4)) + + FOO: { +>FOO : Symbol(FOO, Decl(noInferIntersectedWithEmptyObjectKeyof1.ts, 44, 7)) + + actions: assign({ +>actions : Symbol(actions, Decl(noInferIntersectedWithEmptyObjectKeyof1.ts, 45, 10)) +>assign : Symbol(assign, Decl(noInferIntersectedWithEmptyObjectKeyof1.ts, 25, 2)) + + count: (context) => context.count + 1, +>count : Symbol(count, Decl(noInferIntersectedWithEmptyObjectKeyof1.ts, 46, 23)) +>context : Symbol(context, Decl(noInferIntersectedWithEmptyObjectKeyof1.ts, 47, 16)) +>context.count : Symbol(count, Decl(noInferIntersectedWithEmptyObjectKeyof1.ts, 40, 14)) +>context : Symbol(context, Decl(noInferIntersectedWithEmptyObjectKeyof1.ts, 47, 16)) +>count : Symbol(count, Decl(noInferIntersectedWithEmptyObjectKeyof1.ts, 40, 14)) + + }), + }, + }, +}); + diff --git a/tests/baselines/reference/noInferIntersectedWithEmptyObjectKeyof1.types b/tests/baselines/reference/noInferIntersectedWithEmptyObjectKeyof1.types new file mode 100644 index 0000000000000..f351608d6dc8c --- /dev/null +++ b/tests/baselines/reference/noInferIntersectedWithEmptyObjectKeyof1.types @@ -0,0 +1,181 @@ +//// [tests/cases/conformance/types/typeRelationships/typeInference/noInferIntersectedWithEmptyObjectKeyof1.ts] //// + +=== noInferIntersectedWithEmptyObjectKeyof1.ts === +// https://github.com/microsoft/TypeScript/issues/61091 + +type Keys = keyof (NoInfer<{ foo: string }> & {}); // "foo" +>Keys : "foo" +> : ^^^^^ +>foo : string +> : ^^^^^^ + +type LowInfer = T & {}; +>LowInfer : LowInfer +> : ^^^^^^^^^^^ + +type PropertyAssigner = { +>PropertyAssigner : PropertyAssigner +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^ + + [K in keyof TContext]?: (context: TContext) => TContext[K]; +>context : TContext +> : ^^^^^^^^ + +}; +type Source = { +>Source : Source +> : ^^^^^^ + + count: () => number; +>count : () => number +> : ^^^^^^ + +}; +type Target = PropertyAssigner>>; +>Target : PropertyAssigner>> +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^ +>count : number +> : ^^^^^^ + +declare const source: Source; +>source : Source +> : ^^^^^^ + +const target: Target = source; // ok +>target : PropertyAssigner>> +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^ +>source : Source +> : ^^^^^^ + +type ActionFunction = { +>ActionFunction : ActionFunction +> : ^^^^^^^^^^^^^^^^^^^^^^^^ + + (args: { context: TContext }): void; +>args : { context: TContext; } +> : ^^^^^^^^^^^ ^^^ +>context : TContext +> : ^^^^^^^^ + + _out_TContext?: TContext; +>_out_TContext : TContext | undefined +> : ^^^^^^^^^^^^^^^^^^^^ + +}; + +type TransitionsConfig = Record< +>TransitionsConfig : TransitionsConfig +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + string, + { + actions?: ActionFunction; +>actions : ActionFunction | undefined +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + } +>; + +declare function assign( +>assign : (assignment: PropertyAssigner>) => ActionFunction +> : ^ ^^ ^^ ^^^^^ + + assignment: PropertyAssigner>, +>assignment : PropertyAssigner> +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +): ActionFunction; + +declare function createMachine(config: { +>createMachine : (config: { types?: { context?: TContext; }; on?: TransitionsConfig>; }) => void +> : ^ ^^ ^^ ^^^^^ +>config : { types?: { context?: TContext; }; on?: TransitionsConfig>; } +> : ^^^^^^^^^^ ^^^^^^^ ^^^ + + types?: { +>types : { context?: TContext; } | undefined +> : ^^^^^^^^^^^^ ^^^^^^^^^^^^^^^ + + context?: TContext; +>context : TContext | undefined +> : ^^^^^^^^^^^^^^^^^^^^ + + }; + on?: TransitionsConfig>; +>on : TransitionsConfig> | undefined +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +}): void; + +createMachine({ +>createMachine({ types: { context: { count: 0, }, }, on: { FOO: { actions: assign({ count: (context) => context.count + 1, }), }, },}) : void +> : ^^^^ +>createMachine : (config: { types?: { context?: TContext; }; on?: TransitionsConfig>; }) => void +> : ^ ^^ ^^ ^^^^^ +>{ types: { context: { count: 0, }, }, on: { FOO: { actions: assign({ count: (context) => context.count + 1, }), }, },} : { types: { context: { count: number; }; }; on: { FOO: { actions: ActionFunction>; }; }; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + types: { +>types : { context: { count: number; }; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>{ context: { count: 0, }, } : { context: { count: number; }; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + context: { +>context : { count: number; } +> : ^^^^^^^^^^^^^^^^^^ +>{ count: 0, } : { count: number; } +> : ^^^^^^^^^^^^^^^^^^ + + count: 0, +>count : number +> : ^^^^^^ +>0 : 0 +> : ^ + + }, + }, + on: { +>on : { FOO: { actions: ActionFunction>; }; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>{ FOO: { actions: assign({ count: (context) => context.count + 1, }), }, } : { FOO: { actions: ActionFunction>; }; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + FOO: { +>FOO : { actions: ActionFunction>; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>{ actions: assign({ count: (context) => context.count + 1, }), } : { actions: ActionFunction>; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + actions: assign({ +>actions : ActionFunction> +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>assign({ count: (context) => context.count + 1, }) : ActionFunction> +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>assign : (assignment: PropertyAssigner>) => ActionFunction +> : ^ ^^ ^^ ^^^^^ +>{ count: (context) => context.count + 1, } : { count: (context: LowInfer>) => number; } +> : ^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + count: (context) => context.count + 1, +>count : (context: LowInfer>) => number +> : ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>(context) => context.count + 1 : (context: LowInfer>) => number +> : ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>context : LowInfer> +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>context.count + 1 : number +> : ^^^^^^ +>context.count : number +> : ^^^^^^ +>context : LowInfer> +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>count : number +> : ^^^^^^ +>1 : 1 +> : ^ + + }), + }, + }, +}); + diff --git a/tests/cases/conformance/types/typeRelationships/typeInference/noInferIntersectedWithEmptyObjectKeyof1.ts b/tests/cases/conformance/types/typeRelationships/typeInference/noInferIntersectedWithEmptyObjectKeyof1.ts new file mode 100644 index 0000000000000..b409f9509774e --- /dev/null +++ b/tests/cases/conformance/types/typeRelationships/typeInference/noInferIntersectedWithEmptyObjectKeyof1.ts @@ -0,0 +1,55 @@ +// @strict: true +// @noEmit: true + +// https://github.com/microsoft/TypeScript/issues/61091 + +type Keys = keyof (NoInfer<{ foo: string }> & {}); // "foo" + +type LowInfer = T & {}; +type PropertyAssigner = { + [K in keyof TContext]?: (context: TContext) => TContext[K]; +}; +type Source = { + count: () => number; +}; +type Target = PropertyAssigner>>; +declare const source: Source; +const target: Target = source; // ok + +type ActionFunction = { + (args: { context: TContext }): void; + _out_TContext?: TContext; +}; + +type TransitionsConfig = Record< + string, + { + actions?: ActionFunction; + } +>; + +declare function assign( + assignment: PropertyAssigner>, +): ActionFunction; + +declare function createMachine(config: { + types?: { + context?: TContext; + }; + on?: TransitionsConfig>; +}): void; + +createMachine({ + types: { + context: { + count: 0, + }, + }, + on: { + FOO: { + actions: assign({ + count: (context) => context.count + 1, + }), + }, + }, +});