首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >XState TypeScript - useInterprete服务

XState TypeScript - useInterprete服务
EN

Stack Overflow用户
提问于 2022-03-17 14:03:48
回答 1查看 821关注 0票数 0

我正在使用TypeScriptxStateReact UI相结合构建一个登录机器。

我的机器是:

代码语言:javascript
复制
import { LoginResponse } from 'async/authentication/responseModel';
import Data from 'data';
import { AUTH_TOKEN } from 'Machines/authentication/constants';
import services from 'services';
import { assign, DoneInvokeEvent, Interpreter, Machine, MachineConfig, State } from 'xstate';

export type AutomataContext = {
  authentication: {
    oldToken: {
      exists: boolean;
      token: string;
    };
    token: string;
  };
  login: {
    email: string;
    password: string;
  };
};

export interface AutomataStatesSchema {
  states: {
    SEARCHING_EXISTING_AUTH_TOKEN: {};
    VERIFYING_EXISTING_TOKEN: {};
    LOGIN_VIEW: {};
    AUTHENTICATING: {};
    AUTHENTICATED: {};
    FAILED_AUTH: {};
  };
}

export enum Events {
  ENTER_DATA = 'ENTER_DATA',
  SUBMIT_LOGIN_DATA = 'SUBMIT_LOGIN_DATA',
}

export type SubmitLoginData = {
  type: Events.SUBMIT_LOGIN_DATA;
};

export type EnterData = {
  type: Events.ENTER_DATA;
  value: string;
  field: keyof AutomataContext['login'];
};

export type AutomataEvent = SubmitLoginData | EnterData;
export type AutomataService = Interpreter<AutomataContext, AutomataStatesSchema, AutomataEvent>;

export const enterLoginData = (context: AutomataContext, event: EnterData) => {
  assign({
    login: Object.assign(context.login, { [event.field]: event.value }),
  });
};

export const authenticateUser = (context: AutomataContext, _: any) =>
  services.authenticationService.login(context.login.email, context.login.password);

export const verifyToken = (context: AutomataContext, _: any) =>
  services.authenticationService.validateToken(context.authentication.oldToken.token);

const loginMachineConfig: MachineConfig<AutomataContext, AutomataStatesSchema, AutomataEvent> = {
  id: 'auth-machine',
  initial: 'SEARCHING_EXISTING_AUTH_TOKEN',
  context: {
    authentication: {
      oldToken: {
        exists: false,
        token: '',
      },
      token: '',
    },
    login: {
      email: '',
      password: '',
    },
  },
  on: {
    ENTER_DATA: {
      actions: ['enterLoginData'],
    },
    SUBMIT_LOGIN_DATA: {
      target: 'AUTHENTICATING',
    },
  },
  states: {
    SEARCHING_EXISTING_AUTH_TOKEN: {
      entry: [
        // getTokenFromLocalStorage
        (context, event) => {
          const authentication = Object.assign({}, context.authentication, {
            oldToken: {
              exists: true,
              token: localStorage.getItem(AUTH_TOKEN),
            },
          });
          assign({
            authentication: authentication,
          });
        },
      ],
      after: {
        500: [
          {
            cond: 'doesOldTokenExist',
            target: 'VERIFYING_EXISTING_TOKEN',
          },
          {
            target: 'LOGIN_VIEW',
          },
        ],
      },
      on: {
        ENTER_DATA: undefined,
        SUBMIT_LOGIN_DATA: undefined,
      },
    },
    VERIFYING_EXISTING_TOKEN: {
      invoke: {
        src: 'verifyToken',
        onDone: {
          target: 'AUTHENTICATED',
          actions: [
            // assignExistingTokenToContext
            (context, even) => {
              assign({
                authentication: Object.assign(context.authentication, {
                  token: context.authentication.oldToken.token,
                }),
              });
            },
            //sendLoginDataToStore
            (context, event) => {
              const payload = Data.creators.authentication.saveLoginDataToStore(context.authentication.token);
              Data.store.dispatch(payload);
            },
          ],
        },
        onError: {
          target: 'LOGIN_VIEW',
          actions: [
            // removeExpiredTokenFromStorage
            (context: AutomataContext, event: any) => localStorage.removeItem(AUTH_TOKEN),
          ],
        },
      },
      on: {
        ENTER_DATA: undefined,
        SUBMIT_LOGIN_DATA: undefined,
      },
    },
    LOGIN_VIEW: {},
    AUTHENTICATING: {
      invoke: {
        src: 'authenticateUser',
        onDone: {
          target: 'AUTHENTICATED',
          actions: [
            // clearLoginData
            () =>
              assign({
                login: (context: AutomataContext, event): any =>
                  Object.assign(context.login, { password: '', email: '' }),
              }),
            // assignAuthTokenToContext
            (context: AutomataContext, event: DoneInvokeEvent<LoginResponse>) => {
              assign({
                authentication: Object.assign(context.authentication, {
                  token: event.data.token,
                }),
              });
            },
            // placeAuthTokenToLocalStorage
            (context: AutomataContext, event: any) => localStorage.setItem(AUTH_TOKEN, context.authentication.token),
          ],
        },
      },
      on: {
        ENTER_DATA: undefined,
        SUBMIT_LOGIN_DATA: undefined,
      },
    },
    AUTHENTICATED: {
      on: {
        ENTER_DATA: undefined,
        SUBMIT_LOGIN_DATA: undefined,
      },
    },
    FAILED_AUTH: {},
  },
};

const options: any = {
  services: {
    verifyToken,
    authenticateUser,
  },
  actions: {
    enterLoginData,
  },
  guards: {
    doesOldTokenExist: (context: AutomataContext, _: any) => context.authentication.oldToken.exists === true,
  },
};

export default Machine<AutomataContext, AutomataStatesSchema, AutomataEvent>(loginMachineConfig, options);

在我的反应部分:

index.tsx

代码语言:javascript
复制
import { useInterpret, useMachine } from '@xstate/react';
import machine from 'Machines/authentication/login';
import Form from 'views/routes/authentication/Login/Form';

const Login = () => {

  const loginService = useInterpret(machine);

  return (
    <>
      <Form service={loginService} />
    </>
  );
};

export default Login;

Form.tsx

代码语言:javascript
复制
import { AutomataService } from 'Machines/authentication/login';
import { Link } from 'react-router-dom';

type Props = {
  service: AutomataService;
};

const Form = ({ service }: Props) => {
 //some react code here
}

我在这里得到一个类型错配错误

代码语言:javascript
复制
Type 'Interpreter<AutomataContext, AutomataStatesSchema, AutomataEvent, any, TypegenDisabled & { missingImplementations: { ...; }; } & AllowAllEvents & { ...; }>' is not assignable to type 'AutomataService'.
  The types of 'machine.getStateNodes' are incompatible between these types.
    Type '(state: StateValue | State<AutomataContext, AutomataEvent, any, any, TypegenDisabled & { missingImplementations: { ...; }; } & AllowAllEvents & { ...; }>) => StateNode<...>[]' is not assignable to type '(state: StateValue | State<AutomataContext, AutomataEvent, any, { value: any; context: AutomataContext; }, TypegenDisabled>) => StateNode<...>[]'.
      Types of parameters 'state' and 'state' are incompatible.
        Type 'StateValue | State<AutomataContext, AutomataEvent, any, { value: any; context: AutomataContext; }, TypegenDisabled>' is not assignable to type 'StateValue | State<AutomataContext, AutomataEvent, any, any, TypegenDisabled & { missingImplementations: { ...; }; } & AllowAllEvents & { ...; }>'.
          Type 'State<AutomataContext, AutomataEvent, any, { value: any; context: AutomataContext; }, TypegenDisabled>' is not assignable to type 'StateValue | State<AutomataContext, AutomataEvent, any, any, TypegenDisabled & { missingImplementations: { ...; }; } & AllowAllEvents & { ...; }>'.
            Type 'State<AutomataContext, AutomataEvent, any, { value: any; context: AutomataContext; }, TypegenDisabled>' is not assignable to type 'State<AutomataContext, AutomataEvent, any, any, TypegenDisabled & { missingImplementations: { actions: never; delays: never; guards: never; services: never; }; } & AllowAllEvents & { ...; }>'.
              Types of property 'machine' are incompatible.
                Type 'StateMachine<AutomataContext, any, AutomataEvent, { value: any; context: AutomataContext; }, BaseActionObject, any, TypegenDisabled> | undefined' is not assignable to type 'StateMachine<AutomataContext, any, AutomataEvent, any, BaseActionObject, any, TypegenDisabled & { missingImplementations: { ...; }; } & AllowAllEvents & { ...; }> | undefined'.
                  Type 'StateMachine<AutomataContext, any, AutomataEvent, { value: any; context: AutomataContext; }, BaseActionObject, any, TypegenDisabled>' is not assignable to type 'StateMachine<AutomataContext, any, AutomataEvent, any, BaseActionObject, any, TypegenDisabled & { missingImplementations: { ...; }; } & AllowAllEvents & { ...; }>'.
                    Types of property '__TResolvedTypesMeta' are incompatible.
                      Type 'TypegenDisabled' is not assignable to type 'TypegenDisabled & { missingImplementations: { actions: never; delays: never; guards: never; services: never; }; } & AllowAllEvents & { indexedActions: IndexByType<...>; indexedEvents: Record<...> & { ...; }; invokeSrcNameMap: Record<...>; }'

我在这里迷失了,这个TypeScript错误真正想说的是什么。TypeSystem本身有什么问题吗?还是我把interpreter建错了?

EN

回答 1

Stack Overflow用户

发布于 2022-04-01 01:58:58

我一直这么做的方式是InterpreterFrom<typeof myMachine>。我认为,机器构造函数也存在类型问题。官方推荐的方法是createMachine()

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/71513695

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档