Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
TypeScript 5.2 Beta (devblogs.microsoft.com/typescript)
42 points by DanRosenwasser on June 30, 2023 | hide | past | favorite | 10 comments


I had mixed feelings about using, but I’m into it now. I like seeing familiar conventions from other languages I’ve come to love, and it seems like the implementation will likely deliver the same QOL benefits I’m familiar with.

On that note, I know it’s contentious, but I’d love to see pattern matching baked in like we have it in Rust (or similar). I’ve come to love ts-pattern so much, and I’m constantly wishing it was part of TypeScript/JavaScript.


I can't help but think this is a clunkier than necessary. With function composition and the try/finally approach described we can get the same thing:

    const doSomeWork = () => {
      // some computation here. 
    }

    const withCleanup = (fn, cleanupFn) => {
      let x;
      try { x = fn() }
      finally { cleanupFn() }
      return x; 
    };

    const someCleanupFn = () => {
      // remove that file or whatever...
    };
    
    const doSomeWorkAndCleanup = withCleanup(doSomeWork, someCleanupFn);
    
This also provides lots of nice ways to understand what that cleanup behavior was to the caller. We could return an array of the original function return value and the result of the cleanup function. Maybe this reveals a potential new monadic structure that would be useful...

I agree doing this in OO, like what's shown in the page's examples, without the execution environment's support is tricky... I'd rather see though a new class to handle this rather than adding this behavior by adding a special method - it seems to put us back in the direction of having lifecycle methods like what React supports in class components that the community has totally moved away from.

I think I don't like that triggering the `dispose` method only takes place when the keyword `using` is present. It'd be much cleaner that it is always invoked on any object whose extends `Disposable`. Unless I have that behavior wrong...


How would I access anything locally created inside doSomeWork from my someCleanupFn in this example?


Arguments to the doSomeWork can be carried through to someCleanupFn as can any return values from doSomeWork.

If doSomeWork returns all the pieces that need to be cleaned up by someCleanupFn (or those pieces are part of the original arguments), then those values can also be passed in as arguments to someCleanupFn.

This pattern (passing original arguments through, along with return values, to a supporting function) hints at a more elegant solution as well - a new monadic structure that supports this behavior by default.


This [Symbol.dispose]() stuff is not intuitive to me. What are the brackets for? Is this an object property? Seems like a bad analogue to Swift’s defer and deinit keywords/methods.


Are you familiar with [Symbol.iterator]()? It's doing the same thing.

{[someValue]: ...} is a pattern used when initializing computed keys on objects [1]. Some people might not encounter it often, though.

Symbol.* is sometimes used to implement language-level methods, like Symbol.dispose here or Symbol.iterator in my example below [2]. JS knows what those are for, and has well-defined and documented ways of using them.

I think — and I'm willing to be wrong — it's a pretty useful convention once it clicks, and while it might be confusing at first, I've come to like it. In the iterator example, you can see how you can create a dynamic data structure from a POJO (generating 52 cards from only the suits and ranks of a deck, and being able to treat it like an array). It's a useful way to encapsulate data and logic about a collection of data. When combined with generators, this pattern is extremely powerful. But again, this is why some people might not encounter it often.

1. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...

2. https://codesandbox.io/s/keen-swartz-7yrls3?file=/src/index....


JavaScript allows you to access and define object properties in several ways. The key thing to know here is that obj.foo, obj[“foo”], and obj[myProp] are all equivalent, where foo is a property of obj, and myProp is a variable containing the string “foo”.

This behavior is extended into object and class definitions, too. {[myProp]: “value”} creates an object whose property is the value of myProp, while {myProp: “value”} is an object with the property “myProp”. Because of the special nature of Symbols, the bracket notation is used when creating an object or class whose properties include a Symbol.


It's just a method definition using a globally defined symbol instead of your own method name which may clash with existing "dispose" implementations.

Agreed it's a little weird if you haven't been using variables as method names before though.


Sometimes I sneeze, and within that time alone, Microsoft releases a few new versions of TypeScript.


Well IIRC it’s a 6 week release cycle and has been consistent with that for a while.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: