我正在尝试键入一个函数,该函数返回给定对象的属性的子集。我不确定为什么以下方法不起作用。
const initialState = {
count: 0,
mounted: false,
}
type State = Readonly<typeof initialState>
type Updater<S> = <K extends keyof S>(prevState: S) => Pick<S, K> | null
const increment/* ERROR HERE */: Updater<State> = (prevState: State) => ({
count: prevState.count + 1,
})
我收到以下错误消息。
Type '{ count: number; }' is not assignable to type 'Pick<Readonly<{ count: number; mounted: boolean; }>, K>'.
从react键入setState方法似乎很好用
class Component<P, S> {
...
setState<K extends keyof S>(
state: ((prevState: Readonly<S>, props: P) => (Pick<S, K> | S | null)) | (Pick<S, K> | S | null),
callback?: () => void
): void;
...
}
和
setState(increment)
工作正常,没有任何错误。
这些类型看起来很相似,所以我不太确定出了什么问题。
答案 0 :(得分:1)
函数increment
返回State
的键的特定子集。 Updater
函数将需要返回State
的键的子集,这不是基于它自己的逻辑而是基于传递给它的type参数。
如果我们不在乎返回了State
的哪个子集,我们可以使用Partial<T>
,但这将使该函数对setState
无效,我想这就是重点:
type State = Readonly<typeof initialState>
type Updater<S> = (prevState: S) => Partial<S> | null
const increment: Updater<State> = (prevState: State) => ({
count: prevState.count + 1,
})
class Foo extends React.Component<{}, typeof initialState>
{
foo(){
this.setState(increment(this.state)); // Would be an error because count is number | undefined
}
}
另一种选择是通过将类型参数从函数移至Updater
来固定Updater
中需要返回的键:
type Updater<S, K extends keyof S> = (prevState: S) => Pick<S, K> | null
const increment: Updater<State, 'count'> = (prevState: State) => ({
count: prevState.count + 1,
})
这允许我们使用setState
中的函数,但是我们需要显式指定type参数。最好的选择是使用工厂函数为我们推断K
。
type Updater<S, K extends keyof S> = (prevState: S) => Pick<S, K> | null
function createUpdater<S>() {
return function<K extends keyof S> (fn: (state: S) => Pick<S, K>) : Updater<S, K> {
return fn;
}
}
const increment = createUpdater<State>()((prevState: State) => ({
count: prevState.count + 1,
}));
尽管最好的解决方案可能根本不指定increment
的类型,而让编译器处理所有类型。