直接上代码
class Store<T> {
state: T
constructor(state: T) {
this.state = state
}
get(): T {
return this.state
}
}
function useStore(...arg) {
const stores = arg.slice(0, -1)
const fn = arg.slice(-1)[0]
const state = {}
stores.forEach(([store, getState]) => Object.assign(state, getState(store.get())))
fn(state)
}
const s1 = new Store({ a: 1 })
const s2 = new Store({ b: 2 })
useStore(
[s1, state => ({
a: state.a
})],
[s2, state => ({
c: state.b
})],
...可能有更多,但是格式一致
function (props) {
console.log(props)
}
)
在这里我期望的是,在使用的时候
[s1, state => ({
a: state.a // <- 期望这里能够实现字段的自动提示
})],
function (props) {
// 以及props也能实现字段的自动提示
console.log(props)
}
我也试过
type Cb<T, U> = (state: T) => U
在单个参数的时候是可行的,多个参数的时候就行不通了,ts初学,多参数多回调多类型确实搞不定了,如果有会的希望解答一下,就算改变用法也没关系
这个和 rxjs 的 pipe 有异曲同工之处,参数无限多,每个参数还会影响后续类型推导,这个要做类型推导是无解的,但是有权衡解法。目前只能把简单情况枚举出来,先人肉列出足够多的参数覆盖大部分使用情况,参数再多就 fallback 到丢失类型推导的下策方案。这里当然用到的函数声明类型重载。
实现效果:
线上 typescript playground 版本
第一步 先定义一个辅助类型
useStore
除末尾参数外,每个参数其实都是一个二元组,第一个元素是 Store<T>,第二个是一个接受 T 返回新类型 U 的函数。第二步 从一个 store 一个 fn 的情况开始,逐步列出更多参数的情况
最终列出几个看你自己的需求喽。 一个 store 长这样,记得尾部分号,因为是定义函数重载,函数体在后面。
两个长这样:
三个
最后兜底,防止参数超过定义数量 ts 报错。由于没法定义元素最后一个参数为特定类型,只能这样将就了。或者不定义兜底也行,相当于在 ts 层面不支持无限参数,反正也是 any 乱飞。
合起来: