我目前正在研究高级 TypeScript 类型——我的任务是(在中期)改进 types for rematch .
所以,到目前为止我所做的是:
interface ModelDefinition<TState> {
state: TState;
reducers: TReducers<TState>;
}
interface TReducers<TState> {
[reducerName: string]: TReducer<TState>;
}
type TReducer<TState> = (state: TState, payload: any) => TState;
function createModel<TModelDefinition extends ModelDefinition<TModelDefinition["state"]>>(modelDefinition: TModelDefinition): void {
// ...
}
// Now, this can be used as follows:
createModel({
state: 42,
reducers: {
setValueTo21: (oldState: number, payload: any) => 21
}
});
此时系统会自动检查state是否匹配每个reducer的第一个参数;并且 reducer 返回正确的状态类型。
注意:我故意不使用简单的 TState
泛型参数,因为当类型不匹配时,错误不会显示在不匹配的 reducer 处,而是显示在状态处定义。
对于上述类型,我无法添加一个新属性 effects
,它是一个方法。如果我使用 lambda 语法,它会起作用。
作品:
createModel({
state: 42,
reducers: {
setValueTo21: (oldState: number, payload: any) => 21
},
effects: () => {}
});
休息时间:
createModel({
state: 42,
reducers: {
setValueTo21: (oldState: number, payload: any) => 21
},
effects() {}
});
错误消息显示在 setValueTo21
中:
Type '(oldState: number, payload: any) => number' is not assignable to type 'TReducer<unknown>'.
Types of parameters 'oldState' and 'state' are incompatible.
Type 'unknown' is not assignable to type 'number'. [2322]
再次工作:
有趣的是,当我在函数体外部提取函数定义时,没有发生类型推断错误:
const effects = function() {
}
createModel({
state: 42,
reducers: {
setValueTo21: (oldState: number, payload: any) => 21
},
effects
});
总结
这对我来说真的很奇怪。顺便说一句——我正在运行最新的 TypeScript 版本。任何人都有任何提示,也许我遇到了什么错误? (对我来说,即使在 TypeScript 错误跟踪器中也很难找到可能存在此问题的错误)。
谢谢, 塞巴斯蒂安
最佳答案
这确实看起来像一个错误(可能值得报告),但问题在于您通过访问 ["state"]
将泛型参数约束到自身的方式。您实际上不需要此约束,并且可以使用 any
,当在 extends
子句中使用时,它具有“不受约束”的含义,而不是字面上的“any”。这有效:
function createModel<TModel extends ModelDefinition<any>>(modelDefinition: TModel): void {
// ...
}
关于TypeScript——一些高级类型推断的问题;尝试为 Rematch 构建更好的类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54501901/