Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
unwrap them in canTailRecurse too
Browse files Browse the repository at this point in the history
Andarist committed Jan 30, 2025
1 parent e9939f6 commit 0737761
Showing 4 changed files with 543 additions and 1 deletion.
5 changes: 4 additions & 1 deletion src/compiler/checker.ts
Original file line number Diff line number Diff line change
@@ -19328,7 +19328,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
const typeParamMapper = combineTypeMappers((newType as ConditionalType).mapper, newMapper);
const typeArguments = map(newRoot.outerTypeParameters, t => getMappedType(t, typeParamMapper));
const newRootMapper = createTypeMapper(newRoot.outerTypeParameters, typeArguments);
const newCheckType = newRoot.isDistributive ? getMappedType(newRoot.checkType, newRootMapper) : undefined;
let newCheckType = newRoot.isDistributive ? getMappedType(newRoot.checkType, newRootMapper) : undefined;
if (newCheckType && isNoInferType(newCheckType)) {
newCheckType = (newCheckType as SubstitutionType).baseType;
}
if (!newCheckType || newCheckType === newRoot.checkType || !(newCheckType.flags & (TypeFlags.Union | TypeFlags.Never))) {
root = newRoot;
mapper = newRootMapper;
Original file line number Diff line number Diff line change
@@ -0,0 +1,244 @@
//// [tests/cases/conformance/types/typeRelationships/typeInference/noInferVsDistributiveConditionalType2.ts] ////

=== noInferVsDistributiveConditionalType2.ts ===
type EventObject = {
>EventObject : Symbol(EventObject, Decl(noInferVsDistributiveConditionalType2.ts, 0, 0))

type: string;
>type : Symbol(type, Decl(noInferVsDistributiveConditionalType2.ts, 0, 20))

};

type FooEvent = { type: "FOO" };
>FooEvent : Symbol(FooEvent, Decl(noInferVsDistributiveConditionalType2.ts, 2, 2))
>type : Symbol(type, Decl(noInferVsDistributiveConditionalType2.ts, 4, 17))

type BarEvent = { type: "BAR" };
>BarEvent : Symbol(BarEvent, Decl(noInferVsDistributiveConditionalType2.ts, 4, 32))
>type : Symbol(type, Decl(noInferVsDistributiveConditionalType2.ts, 5, 17))

type Input = FooEvent | BarEvent;
>Input : Symbol(Input, Decl(noInferVsDistributiveConditionalType2.ts, 5, 32))
>FooEvent : Symbol(FooEvent, Decl(noInferVsDistributiveConditionalType2.ts, 2, 2))
>BarEvent : Symbol(BarEvent, Decl(noInferVsDistributiveConditionalType2.ts, 4, 32))

type ExtractEventSimplified<
>ExtractEventSimplified : Symbol(ExtractEventSimplified, Decl(noInferVsDistributiveConditionalType2.ts, 7, 33))

TEvent extends EventObject,
>TEvent : Symbol(TEvent, Decl(noInferVsDistributiveConditionalType2.ts, 9, 28))
>EventObject : Symbol(EventObject, Decl(noInferVsDistributiveConditionalType2.ts, 0, 0))

K extends TEvent["type"],
>K : Symbol(K, Decl(noInferVsDistributiveConditionalType2.ts, 10, 29))
>TEvent : Symbol(TEvent, Decl(noInferVsDistributiveConditionalType2.ts, 9, 28))

> = string extends TEvent["type"] ? TEvent : Extract<TEvent, { type: K }>;
>TEvent : Symbol(TEvent, Decl(noInferVsDistributiveConditionalType2.ts, 9, 28))
>TEvent : Symbol(TEvent, Decl(noInferVsDistributiveConditionalType2.ts, 9, 28))
>Extract : Symbol(Extract, Decl(lib.es5.d.ts, --, --))
>TEvent : Symbol(TEvent, Decl(noInferVsDistributiveConditionalType2.ts, 9, 28))
>type : Symbol(type, Decl(noInferVsDistributiveConditionalType2.ts, 12, 62))
>K : Symbol(K, Decl(noInferVsDistributiveConditionalType2.ts, 10, 29))

type Result = ExtractEventSimplified<NoInfer<Input>, "FOO">;
>Result : Symbol(Result, Decl(noInferVsDistributiveConditionalType2.ts, 12, 74))
>ExtractEventSimplified : Symbol(ExtractEventSimplified, Decl(noInferVsDistributiveConditionalType2.ts, 7, 33))
>NoInfer : Symbol(NoInfer, Decl(lib.es5.d.ts, --, --))
>Input : Symbol(Input, Decl(noInferVsDistributiveConditionalType2.ts, 5, 32))

type EventDescriptorMatches<
>EventDescriptorMatches : Symbol(EventDescriptorMatches, Decl(noInferVsDistributiveConditionalType2.ts, 14, 60))

TEventType extends string,
>TEventType : Symbol(TEventType, Decl(noInferVsDistributiveConditionalType2.ts, 16, 28))

TNormalizedDescriptor,
>TNormalizedDescriptor : Symbol(TNormalizedDescriptor, Decl(noInferVsDistributiveConditionalType2.ts, 17, 28))

> = TEventType extends TNormalizedDescriptor ? true : false;
>TEventType : Symbol(TEventType, Decl(noInferVsDistributiveConditionalType2.ts, 16, 28))
>TNormalizedDescriptor : Symbol(TNormalizedDescriptor, Decl(noInferVsDistributiveConditionalType2.ts, 17, 28))

type PartialEventDescriptor<TEventType extends string> =
>PartialEventDescriptor : Symbol(PartialEventDescriptor, Decl(noInferVsDistributiveConditionalType2.ts, 19, 60))
>TEventType : Symbol(TEventType, Decl(noInferVsDistributiveConditionalType2.ts, 21, 28))

TEventType extends `${infer TLeading}.${infer TTail}`
>TEventType : Symbol(TEventType, Decl(noInferVsDistributiveConditionalType2.ts, 21, 28))
>TLeading : Symbol(TLeading, Decl(noInferVsDistributiveConditionalType2.ts, 22, 29))
>TTail : Symbol(TTail, Decl(noInferVsDistributiveConditionalType2.ts, 22, 47))

? `${TLeading}.*` | `${TLeading}.${PartialEventDescriptor<TTail>}`
>TLeading : Symbol(TLeading, Decl(noInferVsDistributiveConditionalType2.ts, 22, 29))
>TLeading : Symbol(TLeading, Decl(noInferVsDistributiveConditionalType2.ts, 22, 29))
>PartialEventDescriptor : Symbol(PartialEventDescriptor, Decl(noInferVsDistributiveConditionalType2.ts, 19, 60))
>TTail : Symbol(TTail, Decl(noInferVsDistributiveConditionalType2.ts, 22, 47))

: never;

type EventDescriptor<TEvent extends EventObject> =
>EventDescriptor : Symbol(EventDescriptor, Decl(noInferVsDistributiveConditionalType2.ts, 24, 12))
>TEvent : Symbol(TEvent, Decl(noInferVsDistributiveConditionalType2.ts, 26, 21))
>EventObject : Symbol(EventObject, Decl(noInferVsDistributiveConditionalType2.ts, 0, 0))

| TEvent["type"]
>TEvent : Symbol(TEvent, Decl(noInferVsDistributiveConditionalType2.ts, 26, 21))

| PartialEventDescriptor<TEvent["type"]>
>PartialEventDescriptor : Symbol(PartialEventDescriptor, Decl(noInferVsDistributiveConditionalType2.ts, 19, 60))
>TEvent : Symbol(TEvent, Decl(noInferVsDistributiveConditionalType2.ts, 26, 21))

| "*";

type NormalizeDescriptor<TDescriptor extends string> = TDescriptor extends "*"
>NormalizeDescriptor : Symbol(NormalizeDescriptor, Decl(noInferVsDistributiveConditionalType2.ts, 29, 8))
>TDescriptor : Symbol(TDescriptor, Decl(noInferVsDistributiveConditionalType2.ts, 31, 25))
>TDescriptor : Symbol(TDescriptor, Decl(noInferVsDistributiveConditionalType2.ts, 31, 25))

? string
: TDescriptor extends `${infer TLeading}.*`
>TDescriptor : Symbol(TDescriptor, Decl(noInferVsDistributiveConditionalType2.ts, 31, 25))
>TLeading : Symbol(TLeading, Decl(noInferVsDistributiveConditionalType2.ts, 33, 32))

? `${TLeading}.${string}`
>TLeading : Symbol(TLeading, Decl(noInferVsDistributiveConditionalType2.ts, 33, 32))

: TDescriptor;
>TDescriptor : Symbol(TDescriptor, Decl(noInferVsDistributiveConditionalType2.ts, 31, 25))

type ExtractEvent<
>ExtractEvent : Symbol(ExtractEvent, Decl(noInferVsDistributiveConditionalType2.ts, 35, 16))

TEvent extends EventObject,
>TEvent : Symbol(TEvent, Decl(noInferVsDistributiveConditionalType2.ts, 37, 18))
>EventObject : Symbol(EventObject, Decl(noInferVsDistributiveConditionalType2.ts, 0, 0))

TDescriptor extends EventDescriptor<TEvent>,
>TDescriptor : Symbol(TDescriptor, Decl(noInferVsDistributiveConditionalType2.ts, 38, 29))
>EventDescriptor : Symbol(EventDescriptor, Decl(noInferVsDistributiveConditionalType2.ts, 24, 12))
>TEvent : Symbol(TEvent, Decl(noInferVsDistributiveConditionalType2.ts, 37, 18))

> = string extends TEvent["type"]
>TEvent : Symbol(TEvent, Decl(noInferVsDistributiveConditionalType2.ts, 37, 18))

? TEvent
>TEvent : Symbol(TEvent, Decl(noInferVsDistributiveConditionalType2.ts, 37, 18))

: NormalizeDescriptor<TDescriptor> extends infer TNormalizedDescriptor
>NormalizeDescriptor : Symbol(NormalizeDescriptor, Decl(noInferVsDistributiveConditionalType2.ts, 29, 8))
>TDescriptor : Symbol(TDescriptor, Decl(noInferVsDistributiveConditionalType2.ts, 38, 29))
>TNormalizedDescriptor : Symbol(TNormalizedDescriptor, Decl(noInferVsDistributiveConditionalType2.ts, 42, 50))

? TEvent extends any
>TEvent : Symbol(TEvent, Decl(noInferVsDistributiveConditionalType2.ts, 37, 18))

? // true is the check type here to match both true and boolean
true extends EventDescriptorMatches<TEvent["type"], TNormalizedDescriptor>
>EventDescriptorMatches : Symbol(EventDescriptorMatches, Decl(noInferVsDistributiveConditionalType2.ts, 14, 60))
>TEvent : Symbol(TEvent, Decl(noInferVsDistributiveConditionalType2.ts, 37, 18))
>TNormalizedDescriptor : Symbol(TNormalizedDescriptor, Decl(noInferVsDistributiveConditionalType2.ts, 42, 50))

? TEvent
>TEvent : Symbol(TEvent, Decl(noInferVsDistributiveConditionalType2.ts, 37, 18))

: never
: never
: never;

type ActionFunction<
>ActionFunction : Symbol(ActionFunction, Decl(noInferVsDistributiveConditionalType2.ts, 49, 10))

TExpressionEvent extends EventObject,
>TExpressionEvent : Symbol(TExpressionEvent, Decl(noInferVsDistributiveConditionalType2.ts, 51, 20))
>EventObject : Symbol(EventObject, Decl(noInferVsDistributiveConditionalType2.ts, 0, 0))

TEvent extends EventObject,
>TEvent : Symbol(TEvent, Decl(noInferVsDistributiveConditionalType2.ts, 52, 39))
>EventObject : Symbol(EventObject, Decl(noInferVsDistributiveConditionalType2.ts, 0, 0))

> = {
(args: { event: TExpressionEvent }): void;
>args : Symbol(args, Decl(noInferVsDistributiveConditionalType2.ts, 55, 3))
>event : Symbol(event, Decl(noInferVsDistributiveConditionalType2.ts, 55, 10))
>TExpressionEvent : Symbol(TExpressionEvent, Decl(noInferVsDistributiveConditionalType2.ts, 51, 20))

_out_TEvent?: TEvent;
>_out_TEvent : Symbol(_out_TEvent, Decl(noInferVsDistributiveConditionalType2.ts, 55, 44))
>TEvent : Symbol(TEvent, Decl(noInferVsDistributiveConditionalType2.ts, 52, 39))

};

type TransitionsConfig<TEvent extends EventObject> = {
>TransitionsConfig : Symbol(TransitionsConfig, Decl(noInferVsDistributiveConditionalType2.ts, 57, 2))
>TEvent : Symbol(TEvent, Decl(noInferVsDistributiveConditionalType2.ts, 59, 23))
>EventObject : Symbol(EventObject, Decl(noInferVsDistributiveConditionalType2.ts, 0, 0))

[K in EventDescriptor<TEvent>]?: {
>K : Symbol(K, Decl(noInferVsDistributiveConditionalType2.ts, 60, 3))
>EventDescriptor : Symbol(EventDescriptor, Decl(noInferVsDistributiveConditionalType2.ts, 24, 12))
>TEvent : Symbol(TEvent, Decl(noInferVsDistributiveConditionalType2.ts, 59, 23))

actions?: ActionFunction<ExtractEvent<TEvent, K>, TEvent>;
>actions : Symbol(actions, Decl(noInferVsDistributiveConditionalType2.ts, 60, 36))
>ActionFunction : Symbol(ActionFunction, Decl(noInferVsDistributiveConditionalType2.ts, 49, 10))
>ExtractEvent : Symbol(ExtractEvent, Decl(noInferVsDistributiveConditionalType2.ts, 35, 16))
>TEvent : Symbol(TEvent, Decl(noInferVsDistributiveConditionalType2.ts, 59, 23))
>K : Symbol(K, Decl(noInferVsDistributiveConditionalType2.ts, 60, 3))
>TEvent : Symbol(TEvent, Decl(noInferVsDistributiveConditionalType2.ts, 59, 23))

};
};

declare function createMachine<TEvent extends EventObject>(config: {
>createMachine : Symbol(createMachine, Decl(noInferVsDistributiveConditionalType2.ts, 63, 2))
>TEvent : Symbol(TEvent, Decl(noInferVsDistributiveConditionalType2.ts, 65, 31))
>EventObject : Symbol(EventObject, Decl(noInferVsDistributiveConditionalType2.ts, 0, 0))
>config : Symbol(config, Decl(noInferVsDistributiveConditionalType2.ts, 65, 59))

types?: {
>types : Symbol(types, Decl(noInferVsDistributiveConditionalType2.ts, 65, 68))

events?: TEvent;
>events : Symbol(events, Decl(noInferVsDistributiveConditionalType2.ts, 66, 11))
>TEvent : Symbol(TEvent, Decl(noInferVsDistributiveConditionalType2.ts, 65, 31))

};
on?: TransitionsConfig<NoInfer<TEvent>>;
>on : Symbol(on, Decl(noInferVsDistributiveConditionalType2.ts, 68, 4))
>TransitionsConfig : Symbol(TransitionsConfig, Decl(noInferVsDistributiveConditionalType2.ts, 57, 2))
>NoInfer : Symbol(NoInfer, Decl(lib.es5.d.ts, --, --))
>TEvent : Symbol(TEvent, Decl(noInferVsDistributiveConditionalType2.ts, 65, 31))

}): void;

createMachine({
>createMachine : Symbol(createMachine, Decl(noInferVsDistributiveConditionalType2.ts, 63, 2))

types: {
>types : Symbol(types, Decl(noInferVsDistributiveConditionalType2.ts, 72, 15))

events: {} as { type: "FOO" } | { type: "BAR" },
>events : Symbol(events, Decl(noInferVsDistributiveConditionalType2.ts, 73, 10))
>type : Symbol(type, Decl(noInferVsDistributiveConditionalType2.ts, 74, 19))
>type : Symbol(type, Decl(noInferVsDistributiveConditionalType2.ts, 74, 37))

},
on: {
>on : Symbol(on, Decl(noInferVsDistributiveConditionalType2.ts, 75, 4))

FOO: {
>FOO : Symbol(FOO, Decl(noInferVsDistributiveConditionalType2.ts, 76, 7))

actions: ({ event }) => {
>actions : Symbol(actions, Decl(noInferVsDistributiveConditionalType2.ts, 77, 10))
>event : Symbol(event, Decl(noInferVsDistributiveConditionalType2.ts, 78, 17))

event; // { type: "FOO"; }
>event : Symbol(event, Decl(noInferVsDistributiveConditionalType2.ts, 78, 17))

},
},
},
});

208 changes: 208 additions & 0 deletions tests/baselines/reference/noInferVsDistributiveConditionalType2.types
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
//// [tests/cases/conformance/types/typeRelationships/typeInference/noInferVsDistributiveConditionalType2.ts] ////

=== noInferVsDistributiveConditionalType2.ts ===
type EventObject = {
>EventObject : EventObject
> : ^^^^^^^^^^^

type: string;
>type : string
> : ^^^^^^

};

type FooEvent = { type: "FOO" };
>FooEvent : FooEvent
> : ^^^^^^^^
>type : "FOO"
> : ^^^^^

type BarEvent = { type: "BAR" };
>BarEvent : BarEvent
> : ^^^^^^^^
>type : "BAR"
> : ^^^^^

type Input = FooEvent | BarEvent;
>Input : Input
> : ^^^^^

type ExtractEventSimplified<
>ExtractEventSimplified : ExtractEventSimplified<TEvent, K>
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

TEvent extends EventObject,
K extends TEvent["type"],
> = string extends TEvent["type"] ? TEvent : Extract<TEvent, { type: K }>;
>type : K
> : ^

type Result = ExtractEventSimplified<NoInfer<Input>, "FOO">;
>Result : FooEvent
> : ^^^^^^^^

type EventDescriptorMatches<
>EventDescriptorMatches : EventDescriptorMatches<TEventType, TNormalizedDescriptor>
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

TEventType extends string,
TNormalizedDescriptor,
> = TEventType extends TNormalizedDescriptor ? true : false;
>true : true
> : ^^^^
>false : false
> : ^^^^^

type PartialEventDescriptor<TEventType extends string> =
>PartialEventDescriptor : PartialEventDescriptor<TEventType>
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

TEventType extends `${infer TLeading}.${infer TTail}`
? `${TLeading}.*` | `${TLeading}.${PartialEventDescriptor<TTail>}`
: never;

type EventDescriptor<TEvent extends EventObject> =
>EventDescriptor : EventDescriptor<TEvent>
> : ^^^^^^^^^^^^^^^^^^^^^^^

| TEvent["type"]
| PartialEventDescriptor<TEvent["type"]>
| "*";

type NormalizeDescriptor<TDescriptor extends string> = TDescriptor extends "*"
>NormalizeDescriptor : NormalizeDescriptor<TDescriptor>
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

? string
: TDescriptor extends `${infer TLeading}.*`
? `${TLeading}.${string}`
: TDescriptor;

type ExtractEvent<
>ExtractEvent : ExtractEvent<TEvent, TDescriptor>
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

TEvent extends EventObject,
TDescriptor extends EventDescriptor<TEvent>,
> = string extends TEvent["type"]
? TEvent
: NormalizeDescriptor<TDescriptor> extends infer TNormalizedDescriptor
? TEvent extends any
? // true is the check type here to match both true and boolean
true extends EventDescriptorMatches<TEvent["type"], TNormalizedDescriptor>
>true : true
> : ^^^^

? TEvent
: never
: never
: never;

type ActionFunction<
>ActionFunction : ActionFunction<TExpressionEvent, TEvent>
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

TExpressionEvent extends EventObject,
TEvent extends EventObject,
> = {
(args: { event: TExpressionEvent }): void;
>args : { event: TExpressionEvent; }
> : ^^^^^^^^^ ^^^
>event : TExpressionEvent
> : ^^^^^^^^^^^^^^^^

_out_TEvent?: TEvent;
>_out_TEvent : TEvent | undefined
> : ^^^^^^^^^^^^^^^^^^

};

type TransitionsConfig<TEvent extends EventObject> = {
>TransitionsConfig : TransitionsConfig<TEvent>
> : ^^^^^^^^^^^^^^^^^^^^^^^^^

[K in EventDescriptor<TEvent>]?: {
actions?: ActionFunction<ExtractEvent<TEvent, K>, TEvent>;
>actions : ActionFunction<ExtractEvent<TEvent, K>, TEvent> | undefined
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

};
};

declare function createMachine<TEvent extends EventObject>(config: {
>createMachine : <TEvent extends EventObject>(config: { types?: { events?: TEvent; }; on?: TransitionsConfig<NoInfer<TEvent>>; }) => void
> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^
>config : { types?: { events?: TEvent; }; on?: TransitionsConfig<NoInfer<TEvent>>; }
> : ^^^^^^^^^^ ^^^^^^^ ^^^

types?: {
>types : { events?: TEvent; } | undefined
> : ^^^^^^^^^^^ ^^^^^^^^^^^^^^^

events?: TEvent;
>events : TEvent | undefined
> : ^^^^^^^^^^^^^^^^^^

};
on?: TransitionsConfig<NoInfer<TEvent>>;
>on : TransitionsConfig<NoInfer<TEvent>> | undefined
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

}): void;

createMachine({
>createMachine({ types: { events: {} as { type: "FOO" } | { type: "BAR" }, }, on: { FOO: { actions: ({ event }) => { event; // { type: "FOO"; } }, }, },}) : void
> : ^^^^
>createMachine : <TEvent extends EventObject>(config: { types?: { events?: TEvent; }; on?: TransitionsConfig<NoInfer<TEvent>>; }) => void
> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^
>{ types: { events: {} as { type: "FOO" } | { type: "BAR" }, }, on: { FOO: { actions: ({ event }) => { event; // { type: "FOO"; } }, }, },} : { types: { events: { type: "FOO"; } | { type: "BAR"; }; }; on: { FOO: { actions: ({ event }: { event: { type: "FOO"; }; }) => void; }; }; }
> : ^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^

types: {
>types : { events: { type: "FOO"; } | { type: "BAR"; }; }
> : ^^^^^^^^^^ ^^^
>{ events: {} as { type: "FOO" } | { type: "BAR" }, } : { events: { type: "FOO"; } | { type: "BAR"; }; }
> : ^^^^^^^^^^ ^^^

events: {} as { type: "FOO" } | { type: "BAR" },
>events : { type: "FOO"; } | { type: "BAR"; }
> : ^^^^^^^^ ^^^^^^^^^^^^^^ ^^^
>{} as { type: "FOO" } | { type: "BAR" } : { type: "FOO"; } | { type: "BAR"; }
> : ^^^^^^^^ ^^^^^^^^^^^^^^ ^^^
>{} : {}
> : ^^
>type : "FOO"
> : ^^^^^
>type : "BAR"
> : ^^^^^

},
on: {
>on : { FOO: { actions: ({ event }: { event: { type: "FOO"; }; }) => void; }; }
> : ^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^
>{ FOO: { actions: ({ event }) => { event; // { type: "FOO"; } }, }, } : { FOO: { actions: ({ event }: { event: { type: "FOO"; }; }) => void; }; }
> : ^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^

FOO: {
>FOO : { actions: ({ event }: { event: { type: "FOO"; }; }) => void; }
> : ^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^
>{ actions: ({ event }) => { event; // { type: "FOO"; } }, } : { actions: ({ event }: { event: { type: "FOO"; }; }) => void; }
> : ^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^

actions: ({ event }) => {
>actions : ({ event }: { event: { type: "FOO"; }; }) => void
> : ^ ^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^
>({ event }) => { event; // { type: "FOO"; } } : ({ event }: { event: { type: "FOO"; }; }) => void
> : ^ ^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^
>event : { type: "FOO"; }
> : ^^^^^^^^ ^^^

event; // { type: "FOO"; }
>event : { type: "FOO"; }
> : ^^^^^^^^ ^^^

},
},
},
});

Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
// @strict: true
// @noEmit: true

type EventObject = {
type: string;
};

type FooEvent = { type: "FOO" };
type BarEvent = { type: "BAR" };

type Input = FooEvent | BarEvent;

type ExtractEventSimplified<
TEvent extends EventObject,
K extends TEvent["type"],
> = string extends TEvent["type"] ? TEvent : Extract<TEvent, { type: K }>;

type Result = ExtractEventSimplified<NoInfer<Input>, "FOO">;

type EventDescriptorMatches<
TEventType extends string,
TNormalizedDescriptor,
> = TEventType extends TNormalizedDescriptor ? true : false;

type PartialEventDescriptor<TEventType extends string> =
TEventType extends `${infer TLeading}.${infer TTail}`
? `${TLeading}.*` | `${TLeading}.${PartialEventDescriptor<TTail>}`
: never;

type EventDescriptor<TEvent extends EventObject> =
| TEvent["type"]
| PartialEventDescriptor<TEvent["type"]>
| "*";

type NormalizeDescriptor<TDescriptor extends string> = TDescriptor extends "*"
? string
: TDescriptor extends `${infer TLeading}.*`
? `${TLeading}.${string}`
: TDescriptor;

type ExtractEvent<
TEvent extends EventObject,
TDescriptor extends EventDescriptor<TEvent>,
> = string extends TEvent["type"]
? TEvent
: NormalizeDescriptor<TDescriptor> extends infer TNormalizedDescriptor
? TEvent extends any
? // true is the check type here to match both true and boolean
true extends EventDescriptorMatches<TEvent["type"], TNormalizedDescriptor>
? TEvent
: never
: never
: never;

type ActionFunction<
TExpressionEvent extends EventObject,
TEvent extends EventObject,
> = {
(args: { event: TExpressionEvent }): void;
_out_TEvent?: TEvent;
};

type TransitionsConfig<TEvent extends EventObject> = {
[K in EventDescriptor<TEvent>]?: {
actions?: ActionFunction<ExtractEvent<TEvent, K>, TEvent>;
};
};

declare function createMachine<TEvent extends EventObject>(config: {
types?: {
events?: TEvent;
};
on?: TransitionsConfig<NoInfer<TEvent>>;
}): void;

createMachine({
types: {
events: {} as { type: "FOO" } | { type: "BAR" },
},
on: {
FOO: {
actions: ({ event }) => {
event; // { type: "FOO"; }
},
},
},
});

0 comments on commit 0737761

Please sign in to comment.