我有一个状态更新程序功能,该功能可以接收以前的状态,并允许您通过整个对象或功能更新程序设置新状态。例如
const prevState = { x: 3 };
// Option A
const nextState = updateState(prevState, { x: 4 });
// Option B
const nextState = updateState(prevState, prevState => ({ x: prevState.x + 1 }));
我可以在Flow中键入此内容,但不能再使其在TypeScript中工作。这是函数:
function updateState<State>(
prevState: State,
updater: State | ((prevState: State) => State),
): State {
return typeof updater === 'function' ? updater(prevState) : updater;
}
这是错误:
无法调用类型缺少调用签名的表达式。类型'(((prevState:State)=> State)| (状态和功能)'没有兼容的呼叫签名。
(State & Function)
来自哪里?
我的理解是State
本身也可以是一个函数,因为State
是无类型的。但是也许我可以将State
限制为非功能类型...
有什么办法可以使它在TypeScript中起作用?
答案 0 :(得分:2)
问题在于State
是泛型类型参数,因此没有理由State
不能是函数。因此,当您使用类型保护器时,缩小的结果不能从类型中排除State
。类型守卫可以说的是,新类型也将是一个函数,这意味着原始类型与Function
相交,遵循如何扩展这些类型的规则,我们得到:{{1 }}
我们可以做的一件事是确保(State | ((prevState: State) => State)) & Function = (State & Function) | (((prevState: State) => State) & Function ) = (State & Function) | (((prevState: State) => State))
与Function不兼容(没有明确的方法可以说泛型类型不能是特定类型,我们只能说一个类型可以是什么类型) )。
State
该解决方案的一个缺点是约束基本上迫使function updateState<State extends { call?: never } & Record<string, any>>( // if State has a call member it must be never
prevState: State,
updater: State | ((o: State) => State),
): State {
return typeof updater === "function" ? updater(prevState) : updater;
}
成为对象。如果您还希望State
成为基本体,则需要通过并集将基本体添加回去:
State