Live data from Hacker News

Tricks I wish I knew when I learned TypeScript

cstrnt.dev

151–160 of 276 posts

Re: Tricks I wish I knew when I learned TypeScript

#151

Earlier quoted context omitted.

The difference between null and undefined in JavaScript is something I wished had never been implemented. Other languages refer to null as their billion dollar mistake, but somehow JavaScript got 2 of them with slightly different but sometime identical behaviour. I would defer to eslint to prevent this particular issue if you care about it, this allows you to set rules in your own code without any impact to the outsi…

I've always liked the two-nulls solution in JS. `undefined` is a runtime-generated missing value, whereas `null` is a compile-time author-supplied missing value. In other words `undefined` is a "pulled" missing value, `null` a "pushed" missing value. Any feature can be misused, but having the distinction is certainly helpful.

I'm fond of this distinction as well. One could also parse it semantically as `undefined` meaning "unknown unknown" vs `null` being a "known unknown" (or "this value left intentionally blank").

Where I think it falls down in practice, is that JS still treats undefined as a legitimate pseudo-value, as opposed to a read-only return result for a missing key. So for instance, `x=[0,1]` and `x=[0,1,undefined]` will both return undefined for `x[2]`, and it takes jumping through some hoops to know if that value was undefined on purpose, or if the key is simply not found.

If I had my druthers, attempting to set a value as undefined would either throw a fatal error, or be an alternate syntax to unset a value (such that `x.length` would equal 2 in both examples above).

Re: Tricks I wish I knew when I learned TypeScript

#152
post #90

Earlier quoted context omitted.

Typescript is actually a great language. And with those utility types, you can do pretty fun stuff like, for example, you want to mutate a type so that some fields become mandatory: type Ensure = T & { [U in keyof Pick ]-?: T[U] }; class A { foo?: number; bar?: number; baz?: number; } type MandatoryFields = "foo" | "baz"; type B = Ensure ; const b: B = { foo: 42 }; Here, ts will complain that b is missing baz.

This seems extremely hard to read for me, I would have an hard time trying to understand what it does if I found it in any source code

Me, reading the link at the top of this thread: oh wow, those are really cool.

Me, reading this example: oh no, those all need to be added to our project's lint rules to make sure no-one uses them.

Re: Tricks I wish I knew when I learned TypeScript

#153
post #135

Earlier quoted context omitted.

This feels like considerable cognitive load for any developer that needs to work in more than one language.

Most of the implementation details here don't really matter until you need to modify these advanced types directly. That Ensure type definition line in that example is a low level detail that you put in a library somewhere, import throughout your codebase, and then mostly forget about. In practice you'd have someone that understands this set it up once, and then document its usage for others, maybe document the imple…

> In practice you'd have someone that understands this set it up once, and then document its usage for others, maybe document the implementation to make it easier to modify later.

In practice, that someone then leaves the company, leaving this nightmare underfoot.

> The TS compiler is surprisingly good at giving you good readable error messages as well when your code violates these advanced types

Only if you're that original person who understands it! I would still have no idea what is happening, no matter how clear.

Re: Tricks I wish I knew when I learned TypeScript

#154
post #135

Earlier quoted context omitted.

Most of the implementation details here don't really matter until you need to modify these advanced types directly. That Ensure type definition line in that example is a low level detail that you put in a library somewhere, import throughout your codebase, and then mostly forget about. In practice you'd have someone that understands this set it up once, and then document its usage for others, maybe document the imple…

> In practice you'd have someone that understands this set it up once, and then document its usage for others, maybe document the implementation to make it easier to modify later. In practice, that someone then leaves the company, leaving this nightmare underfoot. > The TS compiler is surprisingly good at giving you good readable error messages as well when your code violates these advanced types Only if you're that…

Isn't this true for any abstraction, though? If the person who wrote it is inaccessible, you have to understand it by reading the source.

Re: Tricks I wish I knew when I learned TypeScript

#155
post #139

The third example describes something useful in record types, but goes about it in what seems an odd way, and ends up suboptimal as a result. I'd instead use an object type like this: type Human = { name: string; age: number; } which also enforces value types in the compiler, rather than requiring runtime guards.

The type itself is fine but how it is checked and used is not. The following would be better, and in this case you will also have a Human type inside the forEach callback: // ... other code type Human = { name: string; age: number } const isHuman = (obj: unknown): obj is Human => obj && typeof obj === 'object' && 'name' in obj && 'age' in obj; // you can complete the gaps here and also check the property types someAr…

This is reasonable for validating an untrusted object, sure, but I don't recall that constraint being expressed as part of what the original post was addressing.

Re: Tricks I wish I knew when I learned TypeScript

#156
post #8

Here's another. Instead of returning Sometype|undefined from a function which may or may not have a value to return (such as searchCustomer), return Sometype|null. That forces the function to return a value that's explicitly intended rather than defaulting from a missed out if-else codepath. This is useful since JS is often imperative style code.

The difference between null and undefined in JavaScript is something I wished had never been implemented. Other languages refer to null as their billion dollar mistake, but somehow JavaScript got 2 of them with slightly different but sometime identical behaviour. I would defer to eslint to prevent this particular issue if you care about it, this allows you to set rules in your own code without any impact to the outsi…

> I have only seen null vs undefined lead to 2 things in my experience: mistakes and bikeshedding.

I disagree, though I think the implementation leaves something to be desired. Primarily, I think there is fundamentally a difference between the value of obj.bar in the following examples that is useful to differentiate between:

{ foo: 'hello' }

{ foo: 'hello', bar: null }

For example, GraphQL makes specific use of this when dealing with input types for mutations: null essentially means "delete this field" while unset means "don't change it".

There is a very good discussion on this topic here, https://github.com/graphql/graphql-js/issues/133 , which goes into the rationale behind it, how it's supported in languages that do NOT differentiate between null and undefined, and how some folks changed their minds on the issue.

Re: Tricks I wish I knew when I learned TypeScript

#157

Earlier quoted context omitted.

The grass does seem tend to appear greener in the other paradigm. Barely typed languages like C made rigorously typed languages like C++ and Java seem appealing. The boilerplatiness of those languages made duck typing seem appealing. Writing anything nontrivial with duck typing made more elaborate type systems seem appealing. Needing a PhD in category theory to produce a side effect will no doubt make some other para…

> Needing a PhD in category theory to produce a side effect will no doubt make some other paradigm seem appealing in the future. I think it’s only really Haskell (and perhaps languages like Idris) that’s super strict on side effects. In Rust it’s a simple mut annotation, and perhaps a mutex (and you’ll want that in C too of course) if you’re working across threads.

Does rust have Mut annotations on functions?

I mean, when you look at a problem that monads solve with types is that every function has an “annotation “ of what it uses (IO or mutable state). Similar how async in JS allows await, a state annotation would allow put get or IO annotation any of the IO capabilities.

Of course monads are much more but Mut does not look like it pollutes everything with Mut, including function definitions and results

Re: Tricks I wish I knew when I learned TypeScript

#158

Earlier quoted context omitted.

The grass does seem tend to appear greener in the other paradigm. Barely typed languages like C made rigorously typed languages like C++ and Java seem appealing. The boilerplatiness of those languages made duck typing seem appealing. Writing anything nontrivial with duck typing made more elaborate type systems seem appealing. Needing a PhD in category theory to produce a side effect will no doubt make some other para…

> Barely typed languages like C made rigorously typed languages like C++ and Java seem appealing. The boilerplatiness of those languages made duck typing seem appealing. Eh, I consider Java to be barely typed too. If you have a variable of type Foo, the type system doesn't even guarantee that you have a Foo in there (it might be null). The whole point of a type system, in my mind, is to guarantee that I have that Foo…

I'd love to see an explanation of monads that accurately captures their capabilities in terms no more complex than those required to do the same for promises.

Re: Tricks I wish I knew when I learned TypeScript

#159

Earlier quoted context omitted.

The grass does seem tend to appear greener in the other paradigm. Barely typed languages like C made rigorously typed languages like C++ and Java seem appealing. The boilerplatiness of those languages made duck typing seem appealing. Writing anything nontrivial with duck typing made more elaborate type systems seem appealing. Needing a PhD in category theory to produce a side effect will no doubt make some other para…

> Barely typed languages like C made rigorously typed languages like C++ and Java seem appealing. The boilerplatiness of those languages made duck typing seem appealing. Eh, I consider Java to be barely typed too. If you have a variable of type Foo, the type system doesn't even guarantee that you have a Foo in there (it might be null). The whole point of a type system, in my mind, is to guarantee that I have that Foo…

I would go further. Using monads, or any functional programming concept that you'll encounter in the wild, requires zero category theory. I would actively warn anyone against learning category theory for day-to-day use of FP. Learn it if you're interested in it for its own sake sure, it's a great maths subject, but it's basically irrelevant for most programmers imho and a distraction if you're trying to get a simple practical understanding.

Re: Tricks I wish I knew when I learned TypeScript

#160

Earlier quoted context omitted.

The grass does seem tend to appear greener in the other paradigm. Barely typed languages like C made rigorously typed languages like C++ and Java seem appealing. The boilerplatiness of those languages made duck typing seem appealing. Writing anything nontrivial with duck typing made more elaborate type systems seem appealing. Needing a PhD in category theory to produce a side effect will no doubt make some other para…

> Needing a PhD in category theory to produce a side effect will no doubt make some other paradigm seem appealing in the future. I think it’s only really Haskell (and perhaps languages like Idris) that’s super strict on side effects. In Rust it’s a simple mut annotation, and perhaps a mutex (and you’ll want that in C too of course) if you’re working across threads.

Effects systems in Scala
Post reply on HN