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
One solution could be to enhance type predicates to include syntax for instructing the compiler the new type of a variable and all variables sharing its reference after that call, become the new type.
E.g.
constfooBar : Foo|Bar={ ...
setchangeStateToFoo(value:string): fooBarisFoo{ ... }}asBarconstotherRefToFooBar : Foo|Bar=fooBar// type is `Bar`fooBar.changeStateToFoo='hello'// after this call fooBar is now type `Foo` otherRefToFooBar is now also type `Foo`
This is similar to manual reassignment, but would produce more readable and understandable code. A downside is that this could unintuitively mutate the type of a variable causing the code to be harder to reason about- but as it would produce better code than is currently the case, this remains a better solution what is currently available in Typescript.
π Motivating Example
The ability to manual change a variable or this type, would significant enhance Typescript's ability to model state and state machines.
Despite this being a fairly typical use case, Typescript current doesn't handle the following code well:
typeBar={type: 'bar'changeStateToFoo: string}typeFoo={type: 'foo'sayHello: ()=>void}letfooBar=():Bar=>{return{type: 'bar',setchangeStateToFoo(value:string){delete(fooBarasany).changeStateToFoo;(fooBarasunknownasFoo).type='foo';(fooBarasunknownasFoo).sayHello=()=>console.log(value)//fooBar should now change to type `Foo`}}}constfooBarA=fooBar()fooBarA.changeStateToFoo='Hello, Foo'// after this setter, fooBarA should be type `Foo`fooBarA.sayHello()
Implementing this code in typescript would likely require one of the follow sub optimal solutions:
/** * Workaround One: Type Union * Con: types become a fuzzy merge of multiple types addressing multiple concerns. Causing incorrect type checking in some cases * and requiring superfulous if(exists) checks in other cases. */typeFooBar={type: 'foo'|'bar'sayHello?: ()=>voidchangeStateToFoo?: string}letfooBarB=fooBar()asFooBarfooBarB.changeStateToFoo='Hello, Foo'if(fooBarB.sayHello)fooBarB.sayHello()// con: if required!fooBarB.changeStateToFoo='Hello, Bar'// con: still valid - oops!
or
/** * Workaround Two: Manual Reassignment * Con: requires arbitrary reassignment and requires writer of this code to know * and manually assign the correct type which may be hard to know or complex. */letfooBarC: Foo|Bar=fooBar()fooBarC.changeStateToFoo='Hello, Foo'fooBarC=(fooBarCasunknownasFoo)// con: requires superfluous reassignment and requires writer of this code to know// and manually assign the correct type which may be hard to know or complex for built up generic types.fooBarC.sayHello()fooBarB.changeStateToFoo='Hello, Bar'// pro: correct type checking!
This is already possible with a slightly different variation
interfaceFooBar{type: 'foo'|'bar'sayHello?: ()=>voidchangeStateToFoo(): asserts this is {sayHello(): void}}letfooBarB: FooBar=fooBar()asFooBarfooBarB.changeStateToFoo();fooBarB.sayHello();
I don't think the principle of modifying one property via a setter and causing spooky action at a distance on other properties in the object is common enough to warrant additional modelling.
@RyanCavanaugh Thank you for the third work around - it is a valuable addition to the two I proposed. A key downside is that it only allows narrowing - so it doesn't allow for example an unplacedOrder to become a placedOrder (rather than UnplacedOrder & PlacedOrder) or for a placedOrder to revert back to being an unplacedOrder. I.e. like the other workarounds it also doesn't model state well.
I don't agree with your characterisation of property setters as "causing spooky action at a distance on other properties" being not common. It's kinda the point of setters that setting them changes the object and typescript modelling that well would be valuable and make it a better language.
Suggestion
Provide a way to tell the Typescript Compiler that an object's state has changed - enabling Typescript to model state, and state machines well.
π Search Terms
state
β Viability Checklist
My suggestion meets these guidelines:
β Suggestion
One solution could be to enhance type predicates to include syntax for instructing the compiler the new type of a variable and all variables sharing its reference after that call, become the new type.
E.g.
This is similar to manual reassignment, but would produce more readable and understandable code. A downside is that this could unintuitively mutate the type of a variable causing the code to be harder to reason about- but as it would produce better code than is currently the case, this remains a better solution what is currently available in Typescript.
π Motivating Example
The ability to manual change a variable or this type, would significant enhance Typescript's ability to model state and state machines.
Despite this being a fairly typical use case, Typescript current doesn't handle the following code well:
Implementing this code in typescript would likely require one of the follow sub optimal solutions:
or
code
π» Use Cases
Any code that uses a state machine, or transitions objects between states would significantly benefit from this.
The text was updated successfully, but these errors were encountered: