打字推理问题



我正试图使用React的useReducer和useContext构建一个通用Store,但我在推断默认状态时遇到了问题。

存储生成器功能如下:

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;
}
},
);

问题是generateStoreState泛型不能将自己推断为参数defaultValue的类型。

它总是要求我像这样初始化它,否则intellisense将无法计算出类型: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;
}
},
);

最新更新