reactjs - 打字稿推理问题
问题描述
我正在尝试使用 React 的 useReducer 和 useContext 构建一个通用商店,但我在推断默认状态时遇到了问题。
存储生成器函数如下:
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 && 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
泛型的generateStore
不能将自己推断为参数的类型defaultValue
。
它总是需要我像这样初始化它,否则智能感知将无法计算出类型:
generateStore<StoreActions, typeof defaultState>
关于我如何进行这项工作以及为什么它目前无法推断类型的任何想法?
解决方案
如果您希望 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;
}
},
);
推荐阅读
- tensorflow.js - TensorflowJS:同时训练多个模型(为了性能)
- javascript - android无法从Javascript运行Java函数
- asp.net - .net 中是否有类似节点媒体服务器的 rtmp 实时流媒体库?
- c# - 如何在无尽的跑步游戏中与火箭一起移动相机
- powershell - Powershell 编辑多个受密码保护的 Word 文件
- java - SQL 查询不在 Java 应用程序的服务器端执行
- node.js - 如何在 package-lock.json 中更新依赖版本?
- c - C中的指针,使用数组得到意想不到的结果
- python - python,pandas,按组的自相关
- java - 在方法重载中将字符串作为参数传递