#reactjs #typescript
#reactjs #typescript
Вопрос:
Я пытаюсь создать универсальный магазин, используя useReducer и useContext от React, но у меня возникла проблема с выводом состояния по умолчанию.
Функция генератора хранилища выглядит следующим образом:
export function generateStore<Actions extends ReducerAction, State = any>(defaultValue: State, reducer: (state: State, action: Actions) => State): {
provider: (props: { children: ReactNode }) => ReactElement;
dispatcher: (action: Actions) => void;
useStore: () => State;
} {
const store = createContext(defaultValue);
const { Provider } = store;
let dispatch: React.Dispatch<Actions>;
const ProviderElm = (props: { children: ReactNode }): ReactElement => {
const { children } = props;
const [state, dispatcher] = useReducer(reducer, defaultValue);
dispatch = dispatcher;
return <Provider value={state}>{children}</Provider>;
};
return {
provider: ProviderElm,
dispatcher: (action: Actions) => dispatch amp;amp; dispatch(action),
useStore: () => useContext(store),
};
}
Примером инициализатора может быть:
const defaultState = {
auth: {
authenticated: false,
},
};
type StoreActions =
| {
type: 'LOGIN';
payload: {
token: string;
};
}
| {
type: 'LOGOUT';
};
const { dispatcher, provider, useStore } = generateStore<StoreActions>(
defaultState,
(state = defaultState, action) => {
switch (action.type) {
case 'LOGIN': {
const { token } = action.payload;
return {
...state,
auth: {
authenticated: true,
token,
},
};
}
case 'LOGOUT': {
return {
...state,
auth: {
authenticated: false,
token: null,
},
};
}
default:
return defaultState;
}
},
);
Проблема в том, что State
generic of generateStore
не может вывести себя в качестве typeof параметра defaultValue
.
Это всегда требует, чтобы я инициализировал его следующим образом, иначе intellisense не будет определять тип: generateStore<StoreActions, typeof defaultState>
Есть идеи о том, как я заставляю это работать и почему в настоящее время он не может определить тип?
Ответ №1:
Если вы хотите, чтобы TypeScript выводил ваши общие типы. Вы не можете предоставить функции какие-либо аргументы типа. TypeScript не поддерживает частичный вывод типа. Это все или ничего. Вызывая generateStore<StoreActions>
, вы запускаете компилятор для использования предопределенного State = any
универсального аргумента в вашей функции.
Я бы рекомендовал иметь строго типизированное состояние, чтобы сделать его более чистым.
type State = {
auth: {
authenticated: boolean
}
}
type StoreActions =
| {
type: 'LOGIN';
payload: {
token: string;
};
}
| {
type: 'LOGOUT';
};
const defaultState: State = {
auth: {
authenticated: false,
},
};
const { dispatcher, provider, useStore } = generateStore<StoreActions, State>(
defaultState,
(state = defaultState, action) => {
switch (action.type) {
case 'LOGIN': {
const { token } = action.payload;
return {
...state,
auth: {
authenticated: true,
token,
},
};
}
case 'LOGOUT': {
return {
...state,
auth: {
authenticated: false,
token: null,
},
};
}
default:
return defaultState;
}
},
);
Единственный другой вариант — создать функцию-оболочку, для вывода которой требуется только один аргумент (состояние) и которая напрямую предоставляет тип действий. Вам понадобится по одному для каждого набора действий, но это может быть хорошим решением в зависимости от того, сколько раз оно будет использоваться.
type StoreActions =
| {
type: 'LOGIN';
payload: {
token: string;
};
}
| {
type: 'LOGOUT';
};
const defaultState = {
auth: {
authenticated: false,
},
};
export function generateStoreWithStoreActions<State = any>(defaultValue: State, reducer: (state: State, action: StoreActions) => State) {
return generateStore<StoreActions, State>(defaultValue, reducer);
}
const { dispatcher, provider, useStore } = generateStoreWithStoreActions(
defaultState,
(state = defaultState, action) => {
switch (action.type) {
case 'LOGIN': {
const { token } = action.payload;
return {
...state,
auth: {
authenticated: true,
token,
},
};
}
case 'LOGOUT': {
return {
...state,
auth: {
authenticated: false,
token: null,
},
};
}
default:
return defaultState;
}
},
);
Комментарии:
1. Я понимаю, что вы имеете в виду. Идеальное объяснение. Позор. В любом случае у меня все еще есть обходной путь. Спасибо