TypeScript:在使用泛型键入useReducer时遇到问题



我正在编写一个名为useRequest的自定义挂钩,用于管理数据获取。用户需要传递在promise中解析的数据的类型,以及默认为unknown类型的可选错误类型

以下是实现。


enum Status {
pending = "pending",
resolved = "resolved",
rejected = "rejected"
}
type State<R, E = unknown> = {
status: Status;
data: null | R;
error: null | E;
};
type Action<R, E = unknown> =
| { type: Status.pending }
| { type: Status.resolved; data: R }
| { type: Status.rejected; error: E };
function reducer<R, E>(state: State<R, E>, action: Action<R, E>): State<R, E> {
switch (action.type) {
case Status.pending: {
return { status: Status.pending, data: null, error: null };
}
case Status.resolved: {
return { status: Status.resolved, data: action.data, error: null };
}
case Status.rejected: {
return { status: Status.rejected, data: null, error: action.error };
}
default: {
throw new Error(`unhandled action type`);
}
}
}
function useRequest<R, E = unknown>(intialState: State<R, E>) {
const [state, unsafeDispatch] = React.useReducer(reducer, {
status: Status.pending,
data: null,
error: null,
...intialState
});
// omit implementation details
}

但是,state不是属性类型的,它的类型是State<unknown, unknown>

我试图在现有问题中寻找解决方案,并在useReducer中为返回的参数找到了这种Generic类型。然而,它的方法似乎也不起作用。即


function createReducer<R, E = unknown>() {
return function reducer<R, E>(
state: State<R, E>,
action: Action<R, E>
): State<R, E> {
switch (action.type) {
case Status.pending: {
return { status: Status.pending, data: null, error: null }
}
case Status.resolved: {
return { status: Status.resolved, data: action.data, error: null }
}
case Status.rejected: {
return { status: Status.rejected, data: null, error: action.error }
}
default: {
throw new Error(`unhandled action type`)
}
}
}
}
export default function useRequest<R, E = unknown>(intialState: State<R, E>) {
const reducer = createReducer<R, E>()
const [state, unsafeDispatch] = useReducer(reducer, {
status: Status.pending,
data: null,
error: null,
})

state的类型仍然是State<unknown, unknown>

有人能帮我在这里正确键入useReducer吗?我也在这里寻找任何其他的反馈/建议。谢谢

这是你可以玩的现场演示https://codesandbox.io/s/usereducer-7vvqz

您的reducer函数需要将泛型传递给它,所以让您的reductor返回一个函数

即。

function reducer<R, E>() {
return function actualReducer(state: State<R, E>, action: Action<R, E>): State<R, E> {
...
}
function useRequest<R, E = unknown>(intialState: State<R, E>) {
const [state, unsafeDispatch] = React.useReducer(reducer<R>(), {
...
}
}

请注意,这是在每次渲染时调用一个函数,这可能不是性能性的(您可以将其存储起来以抵消这一点(,但它可以在中工作

编辑:刚刚注意到OP的第二个实现有这个建议,只是把这个答案留在这里,因为它对我有效,并且清楚地突出了实现之间的差异

相关内容

最新更新