какой может быть тип данных полезной нагрузки? - PullRequest
2 голосов
/ 07 апреля 2020

Я использую мутацию graphql:

interface SignInReponse {
  loginEmail : {
    accessToken: number;
  }
}

 const [login] = useMutation<SignInReponse>(LOGIN);

let submitForm = (email: string, password: string) => {
    setIsSubmitted(true);
    login({
      variables: {
        email: email,
        password: password,
      },
    })
      .then(({ data }: ExecutionResult<SignInReponse>) => {
        if (data !== null && data !== undefined){
        dispatch({ type: "login", payload: data.loginEmail.accessToken })  
        setTimeout(_ => {
          setShouldRedirect(true);
        }, 2000)
        setIsLoggedIn(true);
  }})

Мой идентификатор входа в систему:

const initialState = {
    token: null
};

export const loginReducer = (state = initialState, { type, payload } :any) => {
  switch (type) {
    case "login":
      return {...state, token: payload};
    default:
      return state;
  }
};

Я хочу изменить any тип данных в { type, payload } :any и быть более точным c.

Однако я не понимаю, как правильно найти / использовать правильный тип данных. Я уже пробовал использовать SignInResponse, но это не работает, так как тип / полезная нагрузка в нем не упоминаются.

РЕДАКТИРОВАТЬ:

Я также пробовал это:

export const loginReducer = (state = initialState, { type, payload }: {type: "login", payload: string })

но это не похоже на работу.

TypeScript error in /helpers/privateRouting.tsx(7,32):
Property 'token' does not exist on type 'never'.  TS2339

Я изменил такие вещи, но все равно выдает ошибку:

actions / login.ts:

const LOGIN = 'LOGIN'

export interface LoginAction {
    type: typeof LOGIN
    payload: string;
  }

allActions.ts:

import { LoginAction } from './login';

export type AnyAction = LoginAction

Редуктор входа в систему:

const initialState = {
    token: null
};
export const loginReducer = (state = initialState, action: AnyAction) => {
  switch (action.type) {
    case 'LOGIN':
      return {...state, token: action.payload};
    default:
      return state;
  }
};

Редуктор index.ts:

export const rootReducer = combineReducers({
    login: loginReducer,
});

PrivateRouting:

export const PrivateRoute = ({ component, ...rest }: any) => {
  const routeComponent = (props: any) => {
    if (store.getState().login.token) {
      return React.createElement(component, props);
    } else {
      return <Redirect to={{ pathname: '/404' }} />;
    }
  };
  return <Route {...rest} render={routeComponent} />;
};

Ошибка:

Property 'token' does not exist on type 'never'.  TS2339

     5 | export const PrivateRoute = ({ component, ...rest }: any) => {
     6 |   const routeComponent = (props: any) => {
  >  7 |     if (store.getState().login.token) {

Store index.ts:

const persistConfig = {
    key: 'root',
    storage
}

const persistedReducer = persistReducer(persistConfig, rootReducer)

let store = createStore(persistedReducer);
let persistor = persistStore(store);
export { store, persistor };

Я использую privateRoutes, как это:

export default function App() {
  return (
    <Provider store={store}>
      <PersistGate persistor={persistor}>
        <div>
          <BrowserRouter>
            <Switch>
              <Route path="/login" component={LoginPage}></Route>
              <Route path="/404" component={Error404Page}></Route>
              <PrivateRoute
                path="/add"
                component={AddUserPage}
              />
              <Redirect from="*" to="/404" />
            </Switch>
          </BrowserRouter>
        </div>
      </PersistGate>
    </Provider>
  );
}

Ответы [ 2 ]

3 голосов
/ 11 апреля 2020

Это общая тема при использовании Redux с TypeScript. Вы должны использовать объединенный тип, экспортированный из какого-то большого основного actions.ts файла в важном месте. Например:

// somewhere/ComponentOne.tsx
export default ComponentOne = () => stuff;

export interface OneAction {
  type: 'ONE_ACTION';
  payload: string;
}
// all-actions.ts
import { OneAction } from './somewhere/ComponentOne';
import { AnotherAction } from './somewhere/AnotherComponent';

export default type AnyAction = OneAction | AnotherAction;

Тогда в вашем редукторе:

import { AnyAction } from '../../all-actions.ts';

function loginReducer(state = initialState, action: AnyAction) {
  // stuff
}

Теперь ваш редуктор точно знает, что он получает, и безопасность типов идеальна. Эта статья объясняет это намного лучше, чем я, и очень стоит прочитать.

0 голосов
/ 15 апреля 2020

Решение: Добавить интерфейс для initialState и использовать его в качестве параметра типа c для combineReducers.

interface StoreState {
  token: string | null
}
const initialState: StoreState = ...;
export const rootReducer = combineReducers<StoreState>({...})

Причина: Ошибка возникает в store.getState(), а у приставки есть объявление типа для getState() как

/**
 * @template S State object type.
 */
export interface Store<S> {
  //...
  getState(): S;
  //...
}

export const createStore: StoreCreator;
export interface StoreCreator {
  <S>(reducer: Reducer<S>, enhancer?: StoreEnhancer<S>): Store<S>;
  <S>(reducer: Reducer<S>, preloadedState: S, enhancer?: StoreEnhancer<S>): Store<S>;
}

(вы можете найти выше в node_modules/redux/index.d.ts.)

Так это выглядит как в нашем коде не указан параметр типа c generic S для Store<S>. Глядя на приведенный выше код, мы видим, что машинопись должна знать S в Store<S>, если мы укажем ее в вызове createStore, или, лучше, выводить S из функции param reducer: Reducer<S>.

Таким образом, цель теперь состоит в том, чтобы указать S для (любого) параметра в createStore(persistReducer(persistConfig, rootReducer)). Я пропускаю тип persistReducer здесь, но я предполагаю, что он получает S от rootReducer.

Таким образом, цель становится указанием S для combineReducers({login: loginReducer});, тогда как combineReducers имеет подпись:

export function combineReducers<S>(reducers: ReducersMapObject): Reducer<S>;

О! Результат combineReducers (Reducer<S>) может получить S только из явно заданного параметра типа в combineReducers<MyType>(...) (не ссылаясь на параметр функции, как некоторые функции, упомянутые выше). Таким образом, мы указываем это.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...