我整理了一个简单的 Store 实现,它将一个不可变的 javascript 'root' 项包装为状态。
操作允许使用partition
键从父存储中派生子存储。新 Store 的根状态是在该键处找到的原始根状态的子状态。子存储在其他方面的功能与根存储相同。
该实现似乎工作正常,但不幸的是,当(出于其他原因)我需要将可能的根项目限制为extends object
. 当然只有一些子项会满足这个约束,这意味着打字稿会发现递归分区可能出现的错误。
我认为我需要将分区键参数限制为解析为extends object
. 我不确定该怎么做。
在这次干预之前,一切在实施和打字方面都运行良好。
一个看起来积极和编译的定义(在添加对象约束之前)是这个......
type Partitioner<State> = <Key extends keyof State>(key:Key) => Store<State[Key]>;
interface Store<State> {
read():State
write(state:State):void;
partition: Partitioner<State>
}
class BasicStore<State> implements Store<State> {
state:State;
constructor(state:State){
this.state = state;
}
read = () => this.state;
write = (state:State) => this.state = state;
partition:Partitioner<State> = <Key extends keyof State>(key:Key) => new BasicPartition(this, key);
}
export class BasicPartition<State, Key extends keyof State>
implements Store<State[Key]> {
constructor(readonly store: Store<State>, readonly key: Key) {}
read = () => this.store.read()[this.key];
write = (state:State[Key]) => this.store.write({
...this.store.read(),
[this.key]:state
})
partition:Partitioner<State[Key]> = <SubKey extends keyof State[Key]>(subKey:SubKey) => new BasicPartition(this, subKey);
}
编译错误可以在相同代码的以下版本中看到,其中 BasicStore 和 BasicPartition 将它们的状态限制为extends object
...
type Partitioner<State> = <Key extends keyof State>(key:Key) => Store<State[Key]>;
interface Store<State> {
read():State
write(state:State):void;
partition: Partitioner<State>
}
class BasicStore<State extends object> implements Store<State> {
state:State;
constructor(state:State){
this.state = state;
}
read = () => this.state;
write = (state:State) => this.state = state;
partition:Partitioner<State> = <Key extends keyof State>(key:Key) => new BasicPartition(this, key);
}
export class BasicPartition<State extends object, Key extends keyof State>
implements Store<State[Key]> {
constructor(readonly store: Store<State>, readonly key: Key) {}
read = () => this.store.read()[this.key];
write = (state:State[Key]) => this.store.write({
...this.store.read(),
[this.key]:state
})
partition:Partitioner<State[Key]> = <SubKey extends keyof State[Key]>(subKey:SubKey) => new BasicPartition(this, subKey);
}
最后一行报错Argument of type 'this' is not assignable to parameter of type 'Store<object>'
见typescript playground
如何将有效的 Key 参数限制为分区函数,以便 State[Key] 始终是一个对象,从而消除无效的代码路径。在伪代码中,我认为 Partitioner 通用参数可能类似于Key extends keyof State where State[Key] extends object
. 在这个联合解决的never
地方,根本没有有效的论据可供调用partition
。