コンテキスト:TypeStateライブラリを使用して、typescriptで拡張可能ステートマシンを作成するパターンを開発しようとしています。 TypeStateはTypescriptのための型保証された状態マシンを提供しますが、問題の中心ではありませんが、私はそれが私の目標を説明するのを助けています。拡張可能なインターフェイスで使用するための拡張可能な列挙型を作成する
問題:私は活字体でenum
を拡張し、interface
とclass
宣言でそれらを実装するためのスケーラブルなパターンを作成する問題に実行しています。
目標:以下の擬似コードは、自分のパターンがどのように見えるかを示しています。
1)基地enum States
2)States
を用いParentInterface
を定義enum ExtendedStates
2)で得られた追加の状態とenum States
を拡張し、入力したステートマシン
3)ChildInterface
介しParentInterface
を拡張し、States
をオーバーライド定義with ExtendedStates
4)のいずれかのクラスからbroadcastState()
を呼び出し、現在の状態を取得することができる)ChildInterface
6を実装class Child
でclass Parent
を拡張)class Parent
5でParentInterface
を実装します。
私はこのパターンを他の言語でも効果的に使用しています。Typescriptと同じ目標を達成できる代替パターンの限界を理解するのに役立ちます。
import {TypeState} from "typestate";
enum States {
InitialState
}
// extends is not available on enum, looking for alternative
enum ExtendedStates extends States {
AdditionalState
}
/////////////////////////////////////////
// this works fine
interface ParentInterface {
fsm: TypeState.FiniteStateMachine<States>;
states: typeof States;
message: string;
}
// incorrectly extends ParentInterface, types of fsm/states are incompatible
interface ChildInterface extends ParentInterface {
fsm: TypeState.FiniteStateMachine<ExtendedStates>;
states: typeof ExtendedStates;
}
/////////////////////////////////////////
class Parent implements ParentInterface {
public fsm: TypeState.FiniteStateMachine<States>;
public states: typeof States;
public message: string = "The current state is: ";
constructor(state: States | undefined) {
state = state ? state : this.states.InitialState;
this.fsm = new TypeState.FiniteStateMachine(state);
this.broadcastCurrentState();
}
public broadcastCurrentState(): void {
console.log(this.message + this.fsm.currentState);
}
}
class Child extends Parent implements ChildInterface {
public fsm: TypeState.FiniteStateMachine<ExtendedStates>;
public states: typeof ExtendedStates;
constructor(state: ExtendedStates | undefined) {
state = state ? state : this.states.InitialState;
this.fsm = new TypeState.FiniteStateMachine(ExtendedStates);
this.broadcastCurrentState();
}
}
最も近い私が得ている
import {TypeState} from "typestate";
enum States {
InitialState
}
enum ExtendedStates {
InitialState,
ExtendedState
}
class Parent {
public fsm: TypeState.FiniteStateMachine<States>;
public states: typeof States;
public message: string = "The current state is: ";
// T is declared but never used
constructor(state: <T> | undefined) {
state = state ? state : this.states.InitialState;
// cannot find name T
this.fsm = new TypeState.FiniteStateMachine<T>(state);
this.broadcastCurrentState();
}
public broadcastCurrentState(): void {
console.log(this.message + this.fsm.currentState);
}
}
// types of fsm are incompatible
class Child extends Parent {
public fsm: TypeState.FiniteStateMachine<ExtendedStates>;
public states: typeof ExtendedStates;
constructor(state: ExtendedStates | undefined) {
// Param not assignable to type <T>
super(state);
}
}
この試みは、望ましい結果に近づくが、enum
でコードの重複の多くでコンパイルし、結果はありません。また、インターフェースを失いますが、これは要件ではありませんが、安全なネットを提供します。
皆さんのお話が大好きです。私はこれが強力なパターンであると感じています。私はそれを達成するために単純なものが欠けています。
偉大な答え、私はそれがうまくいくと思います。 – gjolund