@@ -9,14 +9,23 @@ declare module 'robot3' {
99 } [ keyof T ]
1010 : never
1111
12- type AllStateKeys < T > = NestedKeys < T > | keyof T
12+ type AllStateKeys < T > = NestedKeys < T > | keyof T ;
13+
14+ type MachineStates < S = { } , F extends string = string > = {
15+ [ K in keyof S ] : {
16+ final : boolean
17+ transitions : Map < string , Transition < F > [ ] >
18+ immediates ?: Map < string , Immediate < F > [ ] >
19+ enter ?: any
20+ }
21+ }
1322
1423 /**
1524 * The debugging object contains an _onEnter method, wich can be set to invoke
1625 * this function on every transition.
1726 */
1827 export const d : {
19- _onEnter ?: OnEnterFunction < Machine >
28+ _onEnter ?: OnEnterFunction < Machine < any > >
2029 }
2130
2231 /**
@@ -27,29 +36,31 @@ declare module 'robot3' {
2736 * @param states - An object of states, where each key is a state name, and the values are one of *state* or *invoke*.
2837 * @param context - A function that returns an object of extended state values. The function can receive an `event` argument.
2938 */
30- export function createMachine < S = { } , C = { } > (
39+ export function createMachine < S extends MachineStates < S , F > , C = { } , F extends string = string > (
3140 initial : keyof S ,
32- states : { [ K in keyof S ] : MachineState } ,
41+ states : S ,
3342 context ?: ContextFunction < C >
34- ) : Machine < typeof states , C , AllStateKeys < S > >
43+ ) : Machine < S , C , AllStateKeys < S > >
3544 /**
3645 * The `createMachine` function creates a state machine. It takes an object of *states* with the key being the state name.
3746 * The value is usually *state* but might also be *invoke*.
3847 *
3948 * @param states - An object of states, where each key is a state name, and the values are one of *state* or *invoke*.
4049 * @param context - A function that returns an object of extended state values. The function can receive an `event` argument.
4150 */
42- export function createMachine < S = { } , C = { } > (
43- states : { [ K in keyof S ] : MachineState } ,
51+ export function createMachine < S extends MachineStates < S , F > , C = { } , F extends string = string > (
52+ states : S ,
4453 context ?: ContextFunction < C >
45- ) : Machine < typeof states , C , AllStateKeys < S > >
54+ ) : Machine < S , C , AllStateKeys < S > > ;
4655
4756 /**
4857 * The `state` function returns a state object. A state can take transitions and immediates as arguments.
4958 *
5059 * @param args - Any argument needs to be of type Transition or Immediate.
5160 */
52- export function state ( ...args : ( Transition | Immediate ) [ ] ) : MachineState
61+ export function state < T extends Transition < any > | Immediate < any > > (
62+ ...args : T [ ]
63+ ) : MachineState < T extends Transition < infer F > ? F : string > ;
5364
5465 /**
5566 * A `transition` function is used to move from one state to another.
@@ -58,11 +69,11 @@ declare module 'robot3' {
5869 * @param state - The name of the destination state.
5970 * @param args - Any extra argument will be evaluated to check if they are one of Reducer, Guard or Action.
6071 */
61- export function transition < C , E > (
62- event : string ,
72+ export function transition < F extends string , C , E > (
73+ event : F ,
6374 state : string ,
6475 ...args : ( Reducer < C , E > | Guard < C , E > | Action < C , E > ) [ ]
65- ) : Transition
76+ ) : Transition < F > ;
6677
6778 /**
6879 * An `immediate` function is a type of transition that occurs immediately; it doesn't wait for an event to proceed.
@@ -71,10 +82,10 @@ declare module 'robot3' {
7182 * @param state - The name of the destination state.
7283 * @param args - Any extra argument will be evaluated to check if they are a Reducer or a Guard.
7384 */
74- export function immediate < C , E > (
85+ export function immediate < F extends string , C , E > (
7586 state : string ,
7687 ...args : ( Reducer < C , E > | Guard < C , E > | Action < C , E > ) [ ]
77- ) : Transition
88+ ) : Transition < F >
7889
7990 /**
8091 * A `guard` is a method that determines if a transition can proceed.
@@ -119,23 +130,23 @@ declare module 'robot3' {
119130 * @param fn - Promise-returning function
120131 * @param args - Any argument needs to be of type Transition or Immediate.
121132 */
122- export function invoke < C , T , E extends { } = any > ( fn : ( ctx : C , e ?: E ) => Promise < T > , ...args : ( Transition | Immediate ) [ ] ) : MachineState
133+ export function invoke < C , T , E extends { } = any > ( fn : ( ctx : C , e ?: E ) => Promise < T > , ...args : ( Transition < any > | Immediate < any > ) [ ] ) : MachineState < any >
123134
124135 /**
125136 * The `invoke` is a special type of state that immediately invokes a Promise-returning or Machine-returning function, or another machine.
126137 *
127138 * @param fn - Machine-returning function
128139 * @param args - Any argument needs to be of type Transition or Immediate.
129140 */
130- export function invoke < C , E extends { } = any , M extends Machine > ( fn : ( ctx : C , e ?: E ) => M , ...args : ( Transition | Immediate ) [ ] ) : MachineState
141+ export function invoke < C , E extends { } = any , M extends Machine = any > ( fn : ( ctx : C , e ?: E ) => M , ...args : ( Transition < any > | Immediate < any > ) [ ] ) : MachineState < any >
131142
132143 /**
133144 * The `invoke` is a special type of state that immediately invokes a Promise-returning or Machine-returning function, or another machine.
134145 *
135146 * @param machine - Machine
136147 * @param args - Any argument needs to be of type Transition or Immediate.
137148 */
138- export function invoke < M extends Machine > ( machine : M , ...args : ( Transition | Immediate ) [ ] ) : MachineState
149+ export function invoke < M extends Machine > ( machine : M , ...args : ( Transition < any > | Immediate < any > ) [ ] ) : MachineState < any >
139150
140151 /* General Types */
141152
@@ -151,8 +162,8 @@ declare module 'robot3' {
151162 service : Service < T >
152163 ) => void
153164
154- export type SendEvent = string | { type : string ; [ key : string ] : any }
155- export type SendFunction < T = SendEvent > = ( event : T ) => void
165+ export type SendEvent < T extends string = string > = T | { type : T ; [ key : string ] : any }
166+ export type SendFunction < T extends string > = ( event : SendEvent < T > & { } ) => void
156167
157168 /**
158169 * This function is invoked before entering a new state and is bound to the debug
@@ -164,16 +175,16 @@ declare module 'robot3' {
164175 * @param prevState - previous state
165176 * @param event - event provoking the state change
166177 */
167- export type OnEnterFunction < M extends Machine > =
178+ export type OnEnterFunction < M extends Machine < any > > =
168179 < C = M [ 'state' ] > ( machine : M , to : string , state : C , prevState : C , event ?: SendEvent ) => void
169180
170- export type Machine < S = { } , C = { } , K = string > = {
181+ export type Machine < S extends MachineStates < S , F > = { } , C = { } , K = string , F extends string = string > = {
171182 context : C
172183 current : K
173184 states : S
174185 state : {
175186 name : K
176- value : MachineState
187+ value : MachineState < F >
177188 }
178189 }
179190
@@ -189,15 +200,15 @@ declare module 'robot3' {
189200 fn : GuardFunction < C , E >
190201 }
191202
192- export interface MachineState {
203+ export interface MachineState < F extends string > {
193204 final : boolean
194- transitions : Map < string , Transition [ ] >
195- immediates ?: Map < string , Immediate [ ] >
205+ transitions : Map < F , Transition < F > [ ] >
206+ immediates ?: Map < F , Immediate < F > [ ] >
196207 enter ?: any
197208 }
198209
199- export interface Transition {
200- from : string | null
210+ export interface Transition < F extends string > {
211+ from : F | null
201212 to : string
202213 guards : any [ ]
203214 reducers : any [ ]
@@ -208,8 +219,30 @@ declare module 'robot3' {
208219 machine : M
209220 context : M [ 'context' ]
210221 onChange : InterpretOnChangeFunction < M >
211- send : SendFunction
222+ send : SendFunction < GetMachineTransitions < M > >
223+ }
224+
225+ export type Immediate < F extends string > = Transition < F > ;
226+
227+ // Utilities
228+ type IsAny < T > = 0 extends ( 1 & T ) ? true : false ;
229+
230+ // Get state objects from a Machine
231+ type GetMachineStateObject < M extends Machine > = M [ 'states' ] ;
232+
233+ // Create mapped type without the final indexing
234+ type GetTransitionsFromStates < S > = {
235+ [ K in keyof S ] : S [ K ] extends { transitions : Map < string , Array < Transition < infer F > > > }
236+ ? IsAny < F > extends true
237+ ? never
238+ : F
239+ : never
212240 }
213241
214- export type Immediate = Transition
242+ type ExtractNonAnyValues < T > = {
243+ [ K in keyof T ] : IsAny < T [ K ] > extends true ? never : T [ K ]
244+ } [ keyof T ] & { } ;
245+
246+ export type GetMachineTransitions < M extends Machine > =
247+ ExtractNonAnyValues < GetTransitionsFromStates < GetMachineStateObject < M > > > ;
215248}
0 commit comments