TypeScript based Promise/A+ compliant, awaitable promise class for Node.js

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP





.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;







up vote
4
down vote

favorite
2












This is yet another Node.js Promise implementation, but this is written in TypeScript, and it strives for type safety and clarity. The full project is located here. Feel free to download it and test it out.



Please give your comments regarding any missing bits or errors, as well as any potential improvements (I'm only 5 days into Node/TypeScript/JavaScript).



function isPromiseLike<T>(x: any): x is PromiseLike<T> 
return x != null && (<PromiseLike<T>>x).then != undefined;


function isPromiseX<T>(x: PromiseLike<T>): x is PromiseX<T>
return x != null && (<PromiseX<T>>x).type == PromiseX.symbolPromiseX;


enum State Pending, Fulfilled, Rejected

export class PromiseX<T = any> implements PromiseLike<T>
static symbolPromiseX: symbol = Symbol('PromiseX');
readonly type: symbol = PromiseX.symbolPromiseX;

private _state: State = State.Pending;

private _result: T;

private _reason: any;

private _continuations: [(x: T) => void, (e: any) => void] = ;

constructor(executor?: (resolve: (value?: T






share|improve this question



























    up vote
    4
    down vote

    favorite
    2












    This is yet another Node.js Promise implementation, but this is written in TypeScript, and it strives for type safety and clarity. The full project is located here. Feel free to download it and test it out.



    Please give your comments regarding any missing bits or errors, as well as any potential improvements (I'm only 5 days into Node/TypeScript/JavaScript).



    function isPromiseLike<T>(x: any): x is PromiseLike<T> 
    return x != null && (<PromiseLike<T>>x).then != undefined;


    function isPromiseX<T>(x: PromiseLike<T>): x is PromiseX<T>
    return x != null && (<PromiseX<T>>x).type == PromiseX.symbolPromiseX;


    enum State Pending, Fulfilled, Rejected

    export class PromiseX<T = any> implements PromiseLike<T>
    static symbolPromiseX: symbol = Symbol('PromiseX');
    readonly type: symbol = PromiseX.symbolPromiseX;

    private _state: State = State.Pending;

    private _result: T;

    private _reason: any;

    private _continuations: [(x: T) => void, (e: any) => void] = ;

    constructor(executor?: (resolve: (value?: T






    share|improve this question























      up vote
      4
      down vote

      favorite
      2









      up vote
      4
      down vote

      favorite
      2






      2





      This is yet another Node.js Promise implementation, but this is written in TypeScript, and it strives for type safety and clarity. The full project is located here. Feel free to download it and test it out.



      Please give your comments regarding any missing bits or errors, as well as any potential improvements (I'm only 5 days into Node/TypeScript/JavaScript).



      function isPromiseLike<T>(x: any): x is PromiseLike<T> 
      return x != null && (<PromiseLike<T>>x).then != undefined;


      function isPromiseX<T>(x: PromiseLike<T>): x is PromiseX<T>
      return x != null && (<PromiseX<T>>x).type == PromiseX.symbolPromiseX;


      enum State Pending, Fulfilled, Rejected

      export class PromiseX<T = any> implements PromiseLike<T>
      static symbolPromiseX: symbol = Symbol('PromiseX');
      readonly type: symbol = PromiseX.symbolPromiseX;

      private _state: State = State.Pending;

      private _result: T;

      private _reason: any;

      private _continuations: [(x: T) => void, (e: any) => void] = ;

      constructor(executor?: (resolve: (value?: T






      share|improve this question













      This is yet another Node.js Promise implementation, but this is written in TypeScript, and it strives for type safety and clarity. The full project is located here. Feel free to download it and test it out.



      Please give your comments regarding any missing bits or errors, as well as any potential improvements (I'm only 5 days into Node/TypeScript/JavaScript).



      function isPromiseLike<T>(x: any): x is PromiseLike<T> 
      return x != null && (<PromiseLike<T>>x).then != undefined;


      function isPromiseX<T>(x: PromiseLike<T>): x is PromiseX<T>
      return x != null && (<PromiseX<T>>x).type == PromiseX.symbolPromiseX;


      enum State Pending, Fulfilled, Rejected

      export class PromiseX<T = any> implements PromiseLike<T>
      static symbolPromiseX: symbol = Symbol('PromiseX');
      readonly type: symbol = PromiseX.symbolPromiseX;

      private _state: State = State.Pending;

      private _result: T;

      private _reason: any;

      private _continuations: [(x: T) => void, (e: any) => void] = ;

      constructor(executor?: (resolve: (value?: T








      share|improve this question












      share|improve this question




      share|improve this question








      edited Jan 14 at 2:56









      Jamal♦

      30.1k11114225




      30.1k11114225









      asked Jan 14 at 2:51









      Dejavu

      1233




      1233




















          1 Answer
          1






          active

          oldest

          votes

















          up vote
          3
          down vote



          accepted










          First, a few notes from your GitHub project



          1. The most important compiler option to turn on is strict. This protects you from many common errors and makes it much nicer when defining optional type parameters. After turning on strict mode, the | undefined part can be dropped from parameters. (Personally, I'd like to also drop null to enforce the use of a consistent. See null is bad)


          2. Consider using a proper testing framework, tests should ideally be quick and easy to read to see exactly what the code should be doing. The current testing code prints out a bunch of numbers without telling me for sure if everything is working or not. I will recommend Ava (potentially along with ava-ts) for the convenience of how it is designed to be used with promises. You could also just use this project to test your implementation.


          Now on to your code :) In no particular order...



          1. Instead of defining a isPromiseX function, you might consider implementing the Symbol.hasInstance method and just using if (x instanceof PromiseX)


          2. With the default promise implementation in Chrome at least, if the passed executor function throws an error, the promise will be rejected. (Does not seem to be covered by the spec). It might be worth duplicating this behavior.


          3. setResult and setError should not be public. They are only used internally.


          4. I prefer early returns to nested code, in every case where you wrap a function's body with if (this._state == State.Pending), I would prefer to check if the state is not pending and return.


          5. The code is not fully spec compliant. See point 2.3.1 is not fulfilled.



          6. Instead of defining setResult and setError as prototype methods, since you pass them into functions it may be worth defining them with arrow functions as demonstrated here.



            private setResult = (result?: T | PromiseLike<T>): void => {


          Good work on the implementation overall!






          share|improve this answer





















          • Thanks for your comments, Gerrit0! I’ll explore the Symbol system and it seems using instanceof is a more intuitive way of doing type guards. This implementation is meant for node.js and server side, so chrome compatibility is not my greatest concern, but your point is taken as a good reference. setResult/setError are public for convenience testing things, so I don’t have to hook them to another “producer”. I like early return too. Honestly, I didn’t really read through the resolution spec, the implementation was largely based on “common sense”, I’ll read through the spec though.
            – Dejavu
            Jan 16 at 6:27










          • Regarding the arrow function, I’m still not too clear regarding the difference between the way I defined them vs the arrow function approach: for the arrow function approach, can I pass “this.setResult” around? Because I knew when I defined it my way, the “this” context was lost, thats why I had to use a closure to wrap it. Thanks again for your suggestions!
            – Dejavu
            Jan 16 at 6:32










          • Oh, regarding the first point (having extra undefined and null union types), the reason is that I'm actually implementing the TypeScript defined PromiseLike<T> interface, whose then method is defined exactly like that. I was not too sure if I should just omit the undefined and null type, so I just included them in, and didn't bother too much.
            – Dejavu
            Jan 16 at 6:37











          • Arrow functions: see the playground
            – Gerrit0
            Jan 16 at 20:37










          Your Answer




          StackExchange.ifUsing("editor", function ()
          return StackExchange.using("mathjaxEditing", function ()
          StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix)
          StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
          );
          );
          , "mathjax-editing");

          StackExchange.ifUsing("editor", function ()
          StackExchange.using("externalEditor", function ()
          StackExchange.using("snippets", function ()
          StackExchange.snippets.init();
          );
          );
          , "code-snippets");

          StackExchange.ready(function()
          var channelOptions =
          tags: "".split(" "),
          id: "196"
          ;
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function()
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled)
          StackExchange.using("snippets", function()
          createEditor();
          );

          else
          createEditor();

          );

          function createEditor()
          StackExchange.prepareEditor(
          heartbeatType: 'answer',
          convertImagesToLinks: false,
          noModals: false,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: null,
          bindNavPrevention: true,
          postfix: "",
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          );



          );








           

          draft saved


          draft discarded


















          StackExchange.ready(
          function ()
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f185078%2ftypescript-based-promise-a-compliant-awaitable-promise-class-for-node-js%23new-answer', 'question_page');

          );

          Post as a guest






























          1 Answer
          1






          active

          oldest

          votes








          1 Answer
          1






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes








          up vote
          3
          down vote



          accepted










          First, a few notes from your GitHub project



          1. The most important compiler option to turn on is strict. This protects you from many common errors and makes it much nicer when defining optional type parameters. After turning on strict mode, the | undefined part can be dropped from parameters. (Personally, I'd like to also drop null to enforce the use of a consistent. See null is bad)


          2. Consider using a proper testing framework, tests should ideally be quick and easy to read to see exactly what the code should be doing. The current testing code prints out a bunch of numbers without telling me for sure if everything is working or not. I will recommend Ava (potentially along with ava-ts) for the convenience of how it is designed to be used with promises. You could also just use this project to test your implementation.


          Now on to your code :) In no particular order...



          1. Instead of defining a isPromiseX function, you might consider implementing the Symbol.hasInstance method and just using if (x instanceof PromiseX)


          2. With the default promise implementation in Chrome at least, if the passed executor function throws an error, the promise will be rejected. (Does not seem to be covered by the spec). It might be worth duplicating this behavior.


          3. setResult and setError should not be public. They are only used internally.


          4. I prefer early returns to nested code, in every case where you wrap a function's body with if (this._state == State.Pending), I would prefer to check if the state is not pending and return.


          5. The code is not fully spec compliant. See point 2.3.1 is not fulfilled.



          6. Instead of defining setResult and setError as prototype methods, since you pass them into functions it may be worth defining them with arrow functions as demonstrated here.



            private setResult = (result?: T | PromiseLike<T>): void => {


          Good work on the implementation overall!






          share|improve this answer





















          • Thanks for your comments, Gerrit0! I’ll explore the Symbol system and it seems using instanceof is a more intuitive way of doing type guards. This implementation is meant for node.js and server side, so chrome compatibility is not my greatest concern, but your point is taken as a good reference. setResult/setError are public for convenience testing things, so I don’t have to hook them to another “producer”. I like early return too. Honestly, I didn’t really read through the resolution spec, the implementation was largely based on “common sense”, I’ll read through the spec though.
            – Dejavu
            Jan 16 at 6:27










          • Regarding the arrow function, I’m still not too clear regarding the difference between the way I defined them vs the arrow function approach: for the arrow function approach, can I pass “this.setResult” around? Because I knew when I defined it my way, the “this” context was lost, thats why I had to use a closure to wrap it. Thanks again for your suggestions!
            – Dejavu
            Jan 16 at 6:32










          • Oh, regarding the first point (having extra undefined and null union types), the reason is that I'm actually implementing the TypeScript defined PromiseLike<T> interface, whose then method is defined exactly like that. I was not too sure if I should just omit the undefined and null type, so I just included them in, and didn't bother too much.
            – Dejavu
            Jan 16 at 6:37











          • Arrow functions: see the playground
            – Gerrit0
            Jan 16 at 20:37














          up vote
          3
          down vote



          accepted










          First, a few notes from your GitHub project



          1. The most important compiler option to turn on is strict. This protects you from many common errors and makes it much nicer when defining optional type parameters. After turning on strict mode, the | undefined part can be dropped from parameters. (Personally, I'd like to also drop null to enforce the use of a consistent. See null is bad)


          2. Consider using a proper testing framework, tests should ideally be quick and easy to read to see exactly what the code should be doing. The current testing code prints out a bunch of numbers without telling me for sure if everything is working or not. I will recommend Ava (potentially along with ava-ts) for the convenience of how it is designed to be used with promises. You could also just use this project to test your implementation.


          Now on to your code :) In no particular order...



          1. Instead of defining a isPromiseX function, you might consider implementing the Symbol.hasInstance method and just using if (x instanceof PromiseX)


          2. With the default promise implementation in Chrome at least, if the passed executor function throws an error, the promise will be rejected. (Does not seem to be covered by the spec). It might be worth duplicating this behavior.


          3. setResult and setError should not be public. They are only used internally.


          4. I prefer early returns to nested code, in every case where you wrap a function's body with if (this._state == State.Pending), I would prefer to check if the state is not pending and return.


          5. The code is not fully spec compliant. See point 2.3.1 is not fulfilled.



          6. Instead of defining setResult and setError as prototype methods, since you pass them into functions it may be worth defining them with arrow functions as demonstrated here.



            private setResult = (result?: T | PromiseLike<T>): void => {


          Good work on the implementation overall!






          share|improve this answer





















          • Thanks for your comments, Gerrit0! I’ll explore the Symbol system and it seems using instanceof is a more intuitive way of doing type guards. This implementation is meant for node.js and server side, so chrome compatibility is not my greatest concern, but your point is taken as a good reference. setResult/setError are public for convenience testing things, so I don’t have to hook them to another “producer”. I like early return too. Honestly, I didn’t really read through the resolution spec, the implementation was largely based on “common sense”, I’ll read through the spec though.
            – Dejavu
            Jan 16 at 6:27










          • Regarding the arrow function, I’m still not too clear regarding the difference between the way I defined them vs the arrow function approach: for the arrow function approach, can I pass “this.setResult” around? Because I knew when I defined it my way, the “this” context was lost, thats why I had to use a closure to wrap it. Thanks again for your suggestions!
            – Dejavu
            Jan 16 at 6:32










          • Oh, regarding the first point (having extra undefined and null union types), the reason is that I'm actually implementing the TypeScript defined PromiseLike<T> interface, whose then method is defined exactly like that. I was not too sure if I should just omit the undefined and null type, so I just included them in, and didn't bother too much.
            – Dejavu
            Jan 16 at 6:37











          • Arrow functions: see the playground
            – Gerrit0
            Jan 16 at 20:37












          up vote
          3
          down vote



          accepted







          up vote
          3
          down vote



          accepted






          First, a few notes from your GitHub project



          1. The most important compiler option to turn on is strict. This protects you from many common errors and makes it much nicer when defining optional type parameters. After turning on strict mode, the | undefined part can be dropped from parameters. (Personally, I'd like to also drop null to enforce the use of a consistent. See null is bad)


          2. Consider using a proper testing framework, tests should ideally be quick and easy to read to see exactly what the code should be doing. The current testing code prints out a bunch of numbers without telling me for sure if everything is working or not. I will recommend Ava (potentially along with ava-ts) for the convenience of how it is designed to be used with promises. You could also just use this project to test your implementation.


          Now on to your code :) In no particular order...



          1. Instead of defining a isPromiseX function, you might consider implementing the Symbol.hasInstance method and just using if (x instanceof PromiseX)


          2. With the default promise implementation in Chrome at least, if the passed executor function throws an error, the promise will be rejected. (Does not seem to be covered by the spec). It might be worth duplicating this behavior.


          3. setResult and setError should not be public. They are only used internally.


          4. I prefer early returns to nested code, in every case where you wrap a function's body with if (this._state == State.Pending), I would prefer to check if the state is not pending and return.


          5. The code is not fully spec compliant. See point 2.3.1 is not fulfilled.



          6. Instead of defining setResult and setError as prototype methods, since you pass them into functions it may be worth defining them with arrow functions as demonstrated here.



            private setResult = (result?: T | PromiseLike<T>): void => {


          Good work on the implementation overall!






          share|improve this answer













          First, a few notes from your GitHub project



          1. The most important compiler option to turn on is strict. This protects you from many common errors and makes it much nicer when defining optional type parameters. After turning on strict mode, the | undefined part can be dropped from parameters. (Personally, I'd like to also drop null to enforce the use of a consistent. See null is bad)


          2. Consider using a proper testing framework, tests should ideally be quick and easy to read to see exactly what the code should be doing. The current testing code prints out a bunch of numbers without telling me for sure if everything is working or not. I will recommend Ava (potentially along with ava-ts) for the convenience of how it is designed to be used with promises. You could also just use this project to test your implementation.


          Now on to your code :) In no particular order...



          1. Instead of defining a isPromiseX function, you might consider implementing the Symbol.hasInstance method and just using if (x instanceof PromiseX)


          2. With the default promise implementation in Chrome at least, if the passed executor function throws an error, the promise will be rejected. (Does not seem to be covered by the spec). It might be worth duplicating this behavior.


          3. setResult and setError should not be public. They are only used internally.


          4. I prefer early returns to nested code, in every case where you wrap a function's body with if (this._state == State.Pending), I would prefer to check if the state is not pending and return.


          5. The code is not fully spec compliant. See point 2.3.1 is not fulfilled.



          6. Instead of defining setResult and setError as prototype methods, since you pass them into functions it may be worth defining them with arrow functions as demonstrated here.



            private setResult = (result?: T | PromiseLike<T>): void => {


          Good work on the implementation overall!







          share|improve this answer













          share|improve this answer



          share|improve this answer











          answered Jan 15 at 23:21









          Gerrit0

          2,6701518




          2,6701518











          • Thanks for your comments, Gerrit0! I’ll explore the Symbol system and it seems using instanceof is a more intuitive way of doing type guards. This implementation is meant for node.js and server side, so chrome compatibility is not my greatest concern, but your point is taken as a good reference. setResult/setError are public for convenience testing things, so I don’t have to hook them to another “producer”. I like early return too. Honestly, I didn’t really read through the resolution spec, the implementation was largely based on “common sense”, I’ll read through the spec though.
            – Dejavu
            Jan 16 at 6:27










          • Regarding the arrow function, I’m still not too clear regarding the difference between the way I defined them vs the arrow function approach: for the arrow function approach, can I pass “this.setResult” around? Because I knew when I defined it my way, the “this” context was lost, thats why I had to use a closure to wrap it. Thanks again for your suggestions!
            – Dejavu
            Jan 16 at 6:32










          • Oh, regarding the first point (having extra undefined and null union types), the reason is that I'm actually implementing the TypeScript defined PromiseLike<T> interface, whose then method is defined exactly like that. I was not too sure if I should just omit the undefined and null type, so I just included them in, and didn't bother too much.
            – Dejavu
            Jan 16 at 6:37











          • Arrow functions: see the playground
            – Gerrit0
            Jan 16 at 20:37
















          • Thanks for your comments, Gerrit0! I’ll explore the Symbol system and it seems using instanceof is a more intuitive way of doing type guards. This implementation is meant for node.js and server side, so chrome compatibility is not my greatest concern, but your point is taken as a good reference. setResult/setError are public for convenience testing things, so I don’t have to hook them to another “producer”. I like early return too. Honestly, I didn’t really read through the resolution spec, the implementation was largely based on “common sense”, I’ll read through the spec though.
            – Dejavu
            Jan 16 at 6:27










          • Regarding the arrow function, I’m still not too clear regarding the difference between the way I defined them vs the arrow function approach: for the arrow function approach, can I pass “this.setResult” around? Because I knew when I defined it my way, the “this” context was lost, thats why I had to use a closure to wrap it. Thanks again for your suggestions!
            – Dejavu
            Jan 16 at 6:32










          • Oh, regarding the first point (having extra undefined and null union types), the reason is that I'm actually implementing the TypeScript defined PromiseLike<T> interface, whose then method is defined exactly like that. I was not too sure if I should just omit the undefined and null type, so I just included them in, and didn't bother too much.
            – Dejavu
            Jan 16 at 6:37











          • Arrow functions: see the playground
            – Gerrit0
            Jan 16 at 20:37















          Thanks for your comments, Gerrit0! I’ll explore the Symbol system and it seems using instanceof is a more intuitive way of doing type guards. This implementation is meant for node.js and server side, so chrome compatibility is not my greatest concern, but your point is taken as a good reference. setResult/setError are public for convenience testing things, so I don’t have to hook them to another “producer”. I like early return too. Honestly, I didn’t really read through the resolution spec, the implementation was largely based on “common sense”, I’ll read through the spec though.
          – Dejavu
          Jan 16 at 6:27




          Thanks for your comments, Gerrit0! I’ll explore the Symbol system and it seems using instanceof is a more intuitive way of doing type guards. This implementation is meant for node.js and server side, so chrome compatibility is not my greatest concern, but your point is taken as a good reference. setResult/setError are public for convenience testing things, so I don’t have to hook them to another “producer”. I like early return too. Honestly, I didn’t really read through the resolution spec, the implementation was largely based on “common sense”, I’ll read through the spec though.
          – Dejavu
          Jan 16 at 6:27












          Regarding the arrow function, I’m still not too clear regarding the difference between the way I defined them vs the arrow function approach: for the arrow function approach, can I pass “this.setResult” around? Because I knew when I defined it my way, the “this” context was lost, thats why I had to use a closure to wrap it. Thanks again for your suggestions!
          – Dejavu
          Jan 16 at 6:32




          Regarding the arrow function, I’m still not too clear regarding the difference between the way I defined them vs the arrow function approach: for the arrow function approach, can I pass “this.setResult” around? Because I knew when I defined it my way, the “this” context was lost, thats why I had to use a closure to wrap it. Thanks again for your suggestions!
          – Dejavu
          Jan 16 at 6:32












          Oh, regarding the first point (having extra undefined and null union types), the reason is that I'm actually implementing the TypeScript defined PromiseLike<T> interface, whose then method is defined exactly like that. I was not too sure if I should just omit the undefined and null type, so I just included them in, and didn't bother too much.
          – Dejavu
          Jan 16 at 6:37





          Oh, regarding the first point (having extra undefined and null union types), the reason is that I'm actually implementing the TypeScript defined PromiseLike<T> interface, whose then method is defined exactly like that. I was not too sure if I should just omit the undefined and null type, so I just included them in, and didn't bother too much.
          – Dejavu
          Jan 16 at 6:37













          Arrow functions: see the playground
          – Gerrit0
          Jan 16 at 20:37




          Arrow functions: see the playground
          – Gerrit0
          Jan 16 at 20:37












           

          draft saved


          draft discarded


























           


          draft saved


          draft discarded














          StackExchange.ready(
          function ()
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f185078%2ftypescript-based-promise-a-compliant-awaitable-promise-class-for-node-js%23new-answer', 'question_page');

          );

          Post as a guest













































































          Popular posts from this blog

          Chat program with C++ and SFML

          Function to Return a JSON Like Objects Using VBA Collections and Arrays

          Will my employers contract hold up in court?