You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
From the first day that we set out to build Microstates, our goal has been to create the most ergonomic tool for working with the state in JavaScript. To accomplish this goal, we have to respond to the changing tides of the JavaScript community to ensure that Microstates is a tool that developers use with their tools of choice.
TypeScript is increasingly becoming a tool of choice for developers working on large projects. Large projects are where Microstates are particularly helpful. By combining TypeScript and Microstates, developers get the benefits of type safety that TypeScript provides and ergonomic runtime state machines that Microstates provide.
TypeScript has been improving quickly and introducing many features that make using Microstates and TypeScript easier and more feasible. Now, we need to make changes to Microstates to bridge the gap and make the two tools work well together.
One of the features that Microstates introduced very early on was a DSL that made it easy to describe Microstates types. Microstates DSL in JavaScript uses class properties to compose one type into another. For example,
classPerson{name=String;age=Number;}
When we create a Microstate from the class Person, Microstates instantiates the Person class to capture references to classes that we composed into the Person class. We later construct Microstates for each of the corresponding classes and assign them into the original Microstate. We used this method because it allowed us to build objects at runtime without requiring an extra transpolation step.
This API works well in JavaScript, but it does not work well with TypeScript. It doesn't work well in TypeScript because TypeScript infers types from the code and it understands this data structure look like this.
classPerson{name: Functionage: Function}
When it encounters an instance of a Person, it assumes that name and age are functions rather than Microstates. To express this correctly in TypeScript, we'd need to write the following.
classPerson{name: String;age: Number;}
In here lies the first challenge. To use Microstates with TypeScript, we need to use TypeScript as the DSL rather than our created DSL. Unfortunately, this is not very simple because when TypeScript compiles classes into JavaScript, it removes all of the information about the actual types. The result looks something like this,
classPerson{}
TypeScript doesn't give us enough information to be able to construct the Microstate at runtime. Likely, this is possible with TypeScript when using decorators and reflect-metadata package. Angular uses this combination for their dependency injection system.
With decorators in TypeScript, our API would look like this.
Internally, @state decorator would tell TypeScript that name is actually a Microstate<StringType>. reflect-metadata would give us the information that we need to build the Microstate.
It is not yet clear how to how to handle transitions in TypeScript. Transitions in Microstates return a different value depending on their type is used. For example,
In Microstates, the type that consumes the StringType dictates the return value of StringType's transitions. This kind of dynamic return value doesn't play well with TypeScript because TypeScript expects that methods return method's return value is static.
It is not yet clear what approach we'll take to making transitions work well in TypeScript, but this should stop us from taking steps towards better TypeScript compatibility. Here is a list of steps that we can take to allow progress to emerge a future solution to the transitions problem.
Introduce a decorator that will provide type information instead of relying on class properties. (class properties DSL will remain in JavaScript but will not be used in TypeScript)
Find a solution to transitions problem
These steps can be shipped incrementally. We'll be happy to support anyone who's interested in moving this forward.
The text was updated successfully, but these errors were encountered:
From the first day that we set out to build Microstates, our goal has been to create the most ergonomic tool for working with the state in JavaScript. To accomplish this goal, we have to respond to the changing tides of the JavaScript community to ensure that Microstates is a tool that developers use with their tools of choice.
TypeScript is increasingly becoming a tool of choice for developers working on large projects. Large projects are where Microstates are particularly helpful. By combining TypeScript and Microstates, developers get the benefits of type safety that TypeScript provides and ergonomic runtime state machines that Microstates provide.
TypeScript has been improving quickly and introducing many features that make using Microstates and TypeScript easier and more feasible. Now, we need to make changes to Microstates to bridge the gap and make the two tools work well together.
One of the features that Microstates introduced very early on was a DSL that made it easy to describe Microstates types. Microstates DSL in JavaScript uses class properties to compose one type into another. For example,
When we create a Microstate from the class
Person,
Microstates instantiates thePerson
class to capture references to classes that we composed into the Person class. We later construct Microstates for each of the corresponding classes and assign them into the original Microstate. We used this method because it allowed us to build objects at runtime without requiring an extra transpolation step.This API works well in JavaScript, but it does not work well with TypeScript. It doesn't work well in TypeScript because TypeScript infers types from the code and it understands this data structure look like this.
When it encounters an instance of a Person, it assumes that
name
andage
are functions rather than Microstates. To express this correctly in TypeScript, we'd need to write the following.In here lies the first challenge. To use Microstates with TypeScript, we need to use TypeScript as the DSL rather than our created DSL. Unfortunately, this is not very simple because when TypeScript compiles classes into JavaScript, it removes all of the information about the actual types. The result looks something like this,
TypeScript doesn't give us enough information to be able to construct the Microstate at runtime. Likely, this is possible with TypeScript when using decorators and reflect-metadata package. Angular uses this combination for their dependency injection system.
With decorators in TypeScript, our API would look like this.
Internally,
@state
decorator would tell TypeScript thatname
is actually aMicrostate<StringType>
.reflect-metadata
would give us the information that we need to build the Microstate.It is not yet clear how to how to handle transitions in TypeScript. Transitions in Microstates return a different value depending on their type is used. For example,
In Microstates, the type that consumes the StringType dictates the return value of StringType's transitions. This kind of dynamic return value doesn't play well with TypeScript because TypeScript expects that methods return method's return value is static.
It is not yet clear what approach we'll take to making transitions work well in TypeScript, but this should stop us from taking steps towards better TypeScript compatibility. Here is a list of steps that we can take to allow progress to emerge a future solution to the transitions problem.
TODO
These steps can be shipped incrementally. We'll be happy to support anyone who's interested in moving this forward.
The text was updated successfully, but these errors were encountered: