Live data from Hacker News

TypeScript 3.7

typescriptlang.org

91–100 of 167 posts

Re: TypeScript 3.7

#91
post #52

I really like the optional chaining operator for statically typed languages. Especially in TypeScript where you have the nullabilaty information baked into the type system. However, in JS itself, it might cause developers to lose track of what can be null/undefined in their code. In case they start to "fix" stuff by throwing in some "?." because they don't know better, the code maintainability will degrade a lot. May…

It's nice for situations where you want to access a deeply nested prop, and you only care whether the whole path is there or not. Saves you having to add a seperate check for every level of the hierarchy. e.g. You can do: foo?.bar?.baz || "default"; Rather than: (foo && foo.bar && foo.bar.baz) || "default"; Agree that developers can be careful about nullability (in fact I pulled someone up on this in a code review ea…

The problem is that if you find yourself needing deep accessors, something is very wrong with your scopes. You are reaching across many levels of concerns which is a code smell.

So, by making it “nice” you are making a code smell less smelly, which feels good in the moment, at the syntax level, but makes your code worse at the architecture level.

This is roughly the story for all of ES6... make it “nice” to work with bad code, allowing bad code to look more similar to good code, until everything looks “nice” at the syntax level but you are surrounded by footguns that are impossible to find, and you need more and more static analysis tools (like TypeScript) to even be able to comprehend your control structures.

Callback hell isn’t bad because of indentation, it’s bad because there are too many handoffs in a small space. Promises make it easier to pack more handoffs into a small space, and guess what? Now the problem is even worse.

This new ? operator will make it easier than ever to pass on undefined values. In other words, it will make the problem it solves even worse.

Re: TypeScript 3.7

#92
post #67

I just did some refactoring on a medium size code base and here are a few things to watch out for when adopting optional chaining and the new null coalescing operator: foo && await foo(); is not the same as await foo?.(); this will work in most cases but subtly, the await wraps the undefined case into a Promise, while the original code would skip the await altogether. String regular expression matching returns null,…

You have to watch out for first and last one in JavaScript but not on TypeScript as it isn't possible to make that mistake because you have to type it as a promise or in the last one as void. You can even avoid the problem in the second one by using NonNullable TypeScript types, but I admit that's not common so its still likely to arise.

The first example can happen in TypeScript; foo has type

  (() => Promise) | undefined
admittedly it may not be all that common to have a function-valued variable that may be undefined, but it happened in the code base I was working with.

In the last example, you're right that TypeScript will catch this at compile time. My point was to show how this compile time error can happen from refactoring to use optional chaining, and one easy solution in this case.

Re: TypeScript 3.7

#93

I'm a big fan of the new operators. One of my remaining gripes with Javascript/Typescript is the try/catch mess around await. It makes assignment of const a pain for async calls that may reject. e.g. let result: SomeType; try { result = await funcThatReturnSomeType(); } catch (err) { doSomethingWithErr(err); } // at this point result is `SomeType | undefined` if (result) { doSomething(result); } I really want some ki…

Another commenter pointed out that .catch is perfectly fine in the async/await world, even though you pretty much never use .then anymore. Here's another way of doing it:

  try {
    doSomething(await funcThatReturnSomeType());
  } catch (err) {
    doSomethingWithErr(err);
  }

Re: TypeScript 3.7

#94
post #93

I'm a big fan of the new operators. One of my remaining gripes with Javascript/Typescript is the try/catch mess around await. It makes assignment of const a pain for async calls that may reject. e.g. let result: SomeType; try { result = await funcThatReturnSomeType(); } catch (err) { doSomethingWithErr(err); } // at this point result is `SomeType | undefined` if (result) { doSomething(result); } I really want some ki…

Another commenter pointed out that .catch is perfectly fine in the async/await world, even though you pretty much never use .then anymore. Here's another way of doing it: try { doSomething(await funcThatReturnSomeType()); } catch (err) { doSomethingWithErr(err); }

They're not equivalent if doSomething might throw and you don't want to catch it.

Re: TypeScript 3.7

#95

I feel really excited about 3.7. Optional chaining and null coalescing will clean up a TON of code. ... but with that being said, 3.7 seems to have broken many aspects of the `Promise.all` interface. Right now the largest issue seems to be that if any `Promise` result in `Promise.all` is nullable, all of the results are nullable.

This is a moment where the postfix `!` operator comes in handy.

It is a well hidden secret, and one that I'm not going to try to lookup the docs for on mobile, but the idea is that the operator strips null/undefined from the type of whatever is before it.

So you can do something like this:

    const [ a, b ] = await Promise.all([
      async () => ({ foo: 'bar' }),
      () => null
    ])

    console.log(a!.foo) // `a!` strips the nullable off `a`

Re: TypeScript 3.7

#96
post #66

Earlier quoted context omitted.

I'm assuming by optional operator you're referring to optional chaining? If so, it's very cool but strikes me as an odd reason to move to TypeScript, because it's a stage 3 proposal in JavaScript too, so is likely to be widely supported soon.

The TypeScript team is only implementing features that have a chance of 100% of landing in JS or 0%. Therefore, they wait for Stage 3. If they start implementing features at an earlier stage, there is the risk of implementing a feature with different semantics in TS than in JS, since the JS spec can still change (or event get rejected). Both cases will result in diverging languages, which is something they try to avo…

Not just Angular, TypeORM and NestJS and a bunch of other server frameworks written in TypeScript make heavy use of decorators. The JavaScript spec for them has been rewritten twice since what TypeScript has so there is going to be a lot of trouble.

Re: TypeScript 3.7

#97
post #79
post #78

Earlier quoted context omitted.

And if you hate the indentation from the `if (result) {}` you can combine this with the poor man's ? operator. const result = await funcThatReturnSomeType().catch(convertError); // result: SomeType | Error if (isError(result)) return result; // now result: SomeType EDIT: the ? operator in question - https://doc.rust-lang.org/edition-guide/rust-2018/error-hand...

You can also get rid of `if(result){}` by setting the return type of "doSomethingWithErr" to "never": function doSomethingWithErr(err: any): never { throw new Error("Oops"); } let result: SomeType; try { result = await funcThatReturnSomeType(); } catch (err) { doSomethingWithErr(err); } // because doSomethingWithErr has return type "never", result will be definitely assigned. doSomething(result); ..or just return in…

Interestingly when I was encountering this myself recently, I discovered that JS finally blocks can return after a function has nominally already returned. Consider the following closure.

    (() => {
      try {
        // finally will return prior to this console.log
        console.log('this try was executed and the return ignored')
        return 'try block'
      } catch (e) {
        return 'error block'
      } finally {
        return 'finally block'
      }  
    })()

Re: TypeScript 3.7

#98

The optional chaining and null coalescing operators are very nice. Dart has had those for several years and they really do come in handy.

Definitely. It's a shame that dart gets so much unwarranted hate. I mean, I also think it's an absolutely awful language but it's really proven to be a valuable source of data for what other programming languages should do and perhaps more importantly: not do. I really hope we see a lot more things like Dart, and not so much negativity.

The use of ?? and ?. for null coalescing and null chaining comes from C#, and predates Dart.

Re: TypeScript 3.7

#99
post #44

I feel really excited about 3.7. Optional chaining and null coalescing will clean up a TON of code. ... but with that being said, 3.7 seems to have broken many aspects of the `Promise.all` interface. Right now the largest issue seems to be that if any `Promise` result in `Promise.all` is nullable, all of the results are nullable.

Indeed, how can you declare a list with some elements nullable, and some not? The result should instead be a tuple, but IDK how well tuple size inference would work in a case like that.

I’m not at a computer now, but you can explicitly define a tuple type like:

    type Tuple = [T, K | null];
Which is my first thought, but I can’t test it against the compiler at the moment and I’m not sure if I’m missing something.

...JavaScript would allow you to extend that list during runtime (unless you freeze it)

    type Tuple = [T, K]
    const Tuple = (x: T, y: K): Tuple => {
        const tup = [x, y];
        Object.freeze(tup);
        return tup;
    };

Re: TypeScript 3.7

#100
post #94
post #93

Earlier quoted context omitted.

Another commenter pointed out that .catch is perfectly fine in the async/await world, even though you pretty much never use .then anymore. Here's another way of doing it: try { doSomething(await funcThatReturnSomeType()); } catch (err) { doSomethingWithErr(err); }

They're not equivalent if doSomething might throw and you don't want to catch it.

Right, which goes back to the question shtylman asked about why doSomething couldn't be part of the try block. I'm tossing this form out there in case it helps. People sometimes forget that await can go wherever an expression goes.
Post reply on HN