#Typing for state.matches

1 messages · Page 1 of 1 (latest)

subtle obsidian
#

I have a utility function for checking if a state matches, but am unsure how to correctly type the parameter.

const generateSelector = (stateMatch: SomeTypeIDontKnow) => {
  return (state: StateFrom<typeof trackMachine>): boolean => {
    return state.matches(stateMatch);
  };
};
dapper warren
#

Not currently possible in v4, unless you're using typegen and want to do some funky typings (let me know if you do)

subtle obsidian
#

We are using typegen, depends how funky the typing is blob_sweat

dapper warren
#

You can use something like typeof state['matches'] - if you have the machine, that's typeof machine['initialState']['matches'] or something like that. You can grab the type of the first arg

subtle obsidian
#

That seems to satisfy the type on the matches(stateMatch), but is throwing the following type error when trying to pass in a string to match against:

import {AnyStateMachine, StateFrom} from 'xstate';

/**
 * Generates a strongly typed selector for determining if a xstate machine
 * is currently in the specified state.
 * @param stateMatcher the string or object to match
 * @returns the xstate selector
 */
export function generateSelector<T extends AnyStateMachine>(
  stateMatcher: T['initialState']['matches']
) {
  return (state: StateFrom<T>) => state.matches(stateMatcher);
}
import {trackMachine} from "../machines/trackMachine";

export type TrackMachine = typeof trackMachine;

export const useIsOpen = (service: TrackService): boolean => {
  return useSelector(service, generateSelector<TrackMachine>('open'));
};

☝️ The open gives this error:

Argument of type 'string' is not assignable to parameter of type '{ <TSV extends "closed" | "open" | "pendingClose">(parentStateValue: TSV): boolean; <TSV extends never>(parentStateValue: TSV): this is State<TrackContext, { type: "openPanel"; } | { type: "closePanel"; } | ... 4 more ... | { ...; }, any, { ...; }, ResolveTypegenMeta<...>> & { ...; }; }'.ts(2345)
dapper warren
#

I'm impressed that you got it working that far... anyway, with TS I think you need to do 'open' as const or something like that

subtle obsidian
#

as const gives the same error unfortunately. In the typegen file there's matchesStates which is a union of the strings I'd expect. Is there a way to get that value from the typeof TrackMachine or similar? (I'm not familiar with how Typegen works under the hood so I'm not sure)

dapper warren
#

Not sure off the top of my head (cc. @brisk geode if you may know the answer)

brisk geode
#

if u want to grab the type accepted by matches

#

perhaps I misunderstood the question though

subtle obsidian
#

That is what I'm trying to do, yes. That's giving me never though. This is what I have in StateFrom<TrackMachine>['matches']

#

But TSV is never when attempting to pull it out of the tuple

brisk geode
#
type StateValuesFrom<T extends AnyStateMachine> = StateFrom<T>['matches'] extends {
  (value: infer StateValues): any
  (value: any): any
} ? StateValues : never
#

smth along those lines should work

#

unfortunately, conditional types in TS only grab the last overload

#

and this one is first, so we have to match against 2 call signatures, to infer from the first one