如何关联高阶函数之间定义的泛型类型?
How do I relate the generic types defined between higher-order functions?
我正在创建一个 Redux store enhancer,它接受一个函数来序列化 Redux 状态。我将构建商店并设置更改订阅 — 在每次更改时,我将序列化状态。对于这个 MCVE,我忽略了订阅方面,只是立即调用序列化函数。
但是,由于函数的高阶性质,我无法将我的状态泛型类型(序列化函数需要)与商店创建者返回的泛型类型相关联:
// Copied and reduced from Redux 4.0.1
type Reducer<S = any> = (
state: S | undefined,
) => S
type DeepPartial<T> = { [K in keyof T]?: DeepPartial<T[K]> }
interface Store<S = any> {
getState(): S
}
type StoreEnhancer<Ext = {}, StateExt = {}> = (
next: StoreEnhancerStoreCreator
) => StoreEnhancerStoreCreator<Ext, StateExt>
type StoreEnhancerStoreCreator<Ext = {}, StateExt = {}> = <
S = any,
>(
reducer: Reducer<S>,
preloadedState?: DeepPartial<S>
) => Store<S & StateExt> & Ext
// My reduced code
interface Config<S> {
serialize: (state: S) => string;
}
const storage = <S>(config: Config<S>): StoreEnhancer => createStore => (reducer, preloadedState) => {
const { serialize } = config;
const theStore = createStore(reducer, preloadedState);
const state = theStore.getState();
const serializedState = serialize(state);
return theStore;
}
错误是:
const serializedState = serialize(state);
^~~~~
Argument of type 'S & {}' is not assignable to parameter of type 'S'.
错误消息很烦人,因为我很确定这两个 S
是无关的;将 StoreEnhancerStoreCreator
中的定义更改为使用 X
而不是 S
会更改此错误消息。
如何将泛型类型参数与 StoreEnhancerStoreCreator
上定义的泛型参数连接起来?
问题是 storage
被声明为(间接地,通过 StoreEnhancer
)return a StoreEnhancerStoreCreator
,这是一个通用函数,必须适用于所有 S
。但是,对 storage
的给定调用会生成一个仅适用于一个 S
的商店创建者:已传递的 config
的 S
。
在我看来,生成 StoreEnhancerStoreCreator
的唯一方法是从 serialize
函数开始,该函数本身在 S
中是通用的。我不确定这在您的场景中是否有意义。也许熟悉 Redux 的人会更清楚该怎么做。
我同意@matt-mccutchen 指出的问题。 StoreEnhancerStoreCreator
是一个泛型函数,所以 (reducer, preloadedState) => {
是一个带有 S
泛型类型参数的泛型函数,这就是编译器报告两个 S
类型之间不兼容的原因。
我建议的解决方案是 StoreEnhancerStoreCreator
不是通用的,据我所知,reducer 和有效负载应该具有与 Config
相同的通用类型参数。此解决方案需要向 StoreEnhancerStoreCreator
和 StoreEnhancer
:
添加一个额外的类型参数
type Reducer<S = any> = (
state: S | undefined,
) => S
type DeepPartial<T> = { [K in keyof T]?: DeepPartial<T[K]> }
interface Store<S = any> {
getState(): S
}
type StoreEnhancer<S, Ext = {}, StateExt = {}> = (
next: StoreEnhancerStoreCreator<S>
) => StoreEnhancerStoreCreator<S, Ext, StateExt>
type StoreEnhancerStoreCreator<S, Ext = {}, StateExt = {}> = (
reducer: Reducer<S>,
preloadedState?: DeepPartial<S>
) => Store<S> & Ext
// My Code
interface Config<S> {
serialize: (state: S) => string;
}
const storage = <S>(config: Config<S>): StoreEnhancer<S> => createStore => (reducer, preloadedState) => {
const { serialize } = config;
const theStore = createStore(reducer, preloadedState);
const state = theStore.getState();
const serializedState = serialize(state);
return theStore;
}
让我走上正轨:
This solution requires adding an extra type parameter to StoreEnhancerStoreCreator
and StoreEnhancer
但是,合适的类型参数已经存在;我只是不明白如何正确使用它。具体来说,a StoreEnhancer
returns a StoreEnhancerStoreCreator
具有默认类型参数。如果我改为设置类型参数,我现在知道将返回哪种状态:
const storage = <S>(config: Config<S>): StoreEnhancer =>
(createStore: StoreEnhancerStoreCreator<{}, S>) =>
// ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ set this type
(reducer, preloadedState) => {
我正在创建一个 Redux store enhancer,它接受一个函数来序列化 Redux 状态。我将构建商店并设置更改订阅 — 在每次更改时,我将序列化状态。对于这个 MCVE,我忽略了订阅方面,只是立即调用序列化函数。
但是,由于函数的高阶性质,我无法将我的状态泛型类型(序列化函数需要)与商店创建者返回的泛型类型相关联:
// Copied and reduced from Redux 4.0.1
type Reducer<S = any> = (
state: S | undefined,
) => S
type DeepPartial<T> = { [K in keyof T]?: DeepPartial<T[K]> }
interface Store<S = any> {
getState(): S
}
type StoreEnhancer<Ext = {}, StateExt = {}> = (
next: StoreEnhancerStoreCreator
) => StoreEnhancerStoreCreator<Ext, StateExt>
type StoreEnhancerStoreCreator<Ext = {}, StateExt = {}> = <
S = any,
>(
reducer: Reducer<S>,
preloadedState?: DeepPartial<S>
) => Store<S & StateExt> & Ext
// My reduced code
interface Config<S> {
serialize: (state: S) => string;
}
const storage = <S>(config: Config<S>): StoreEnhancer => createStore => (reducer, preloadedState) => {
const { serialize } = config;
const theStore = createStore(reducer, preloadedState);
const state = theStore.getState();
const serializedState = serialize(state);
return theStore;
}
错误是:
const serializedState = serialize(state);
^~~~~
Argument of type 'S & {}' is not assignable to parameter of type 'S'.
错误消息很烦人,因为我很确定这两个 S
是无关的;将 StoreEnhancerStoreCreator
中的定义更改为使用 X
而不是 S
会更改此错误消息。
如何将泛型类型参数与 StoreEnhancerStoreCreator
上定义的泛型参数连接起来?
问题是 storage
被声明为(间接地,通过 StoreEnhancer
)return a StoreEnhancerStoreCreator
,这是一个通用函数,必须适用于所有 S
。但是,对 storage
的给定调用会生成一个仅适用于一个 S
的商店创建者:已传递的 config
的 S
。
在我看来,生成 StoreEnhancerStoreCreator
的唯一方法是从 serialize
函数开始,该函数本身在 S
中是通用的。我不确定这在您的场景中是否有意义。也许熟悉 Redux 的人会更清楚该怎么做。
我同意@matt-mccutchen 指出的问题。 StoreEnhancerStoreCreator
是一个泛型函数,所以 (reducer, preloadedState) => {
是一个带有 S
泛型类型参数的泛型函数,这就是编译器报告两个 S
类型之间不兼容的原因。
我建议的解决方案是 StoreEnhancerStoreCreator
不是通用的,据我所知,reducer 和有效负载应该具有与 Config
相同的通用类型参数。此解决方案需要向 StoreEnhancerStoreCreator
和 StoreEnhancer
:
type Reducer<S = any> = (
state: S | undefined,
) => S
type DeepPartial<T> = { [K in keyof T]?: DeepPartial<T[K]> }
interface Store<S = any> {
getState(): S
}
type StoreEnhancer<S, Ext = {}, StateExt = {}> = (
next: StoreEnhancerStoreCreator<S>
) => StoreEnhancerStoreCreator<S, Ext, StateExt>
type StoreEnhancerStoreCreator<S, Ext = {}, StateExt = {}> = (
reducer: Reducer<S>,
preloadedState?: DeepPartial<S>
) => Store<S> & Ext
// My Code
interface Config<S> {
serialize: (state: S) => string;
}
const storage = <S>(config: Config<S>): StoreEnhancer<S> => createStore => (reducer, preloadedState) => {
const { serialize } = config;
const theStore = createStore(reducer, preloadedState);
const state = theStore.getState();
const serializedState = serialize(state);
return theStore;
}
This solution requires adding an extra type parameter to
StoreEnhancerStoreCreator
andStoreEnhancer
但是,合适的类型参数已经存在;我只是不明白如何正确使用它。具体来说,a StoreEnhancer
returns a StoreEnhancerStoreCreator
具有默认类型参数。如果我改为设置类型参数,我现在知道将返回哪种状态:
const storage = <S>(config: Config<S>): StoreEnhancer =>
(createStore: StoreEnhancerStoreCreator<{}, S>) =>
// ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ set this type
(reducer, preloadedState) => {