Live data from Hacker News

Tricks I wish I knew when I learned TypeScript

cstrnt.dev

211–220 of 276 posts

Re: Tricks I wish I knew when I learned TypeScript

#211
post #201

Earlier quoted context omitted.

Right, but the actual benefit comes from having the REPL and the debugger in the same place. Plus the chrome REPL is fantastic, so suggesting I just use a different one is sorta like saying "you can just use your phone" when my default is a Hasselblad. When I'm writing JS/Node I can write code in the REPL in the context within which it will execute, it really cuts down on how much I have to hold in my head at one tim…

Not sure if this solves 100% of your problems, but this seems like it could help a bit https://chrome.google.com/webstore/detail/typescript-console... Also for me, the benefits of a statically typed language on a large team heavily outweighs not having TS in a chrome REPL. It's not even close. Maybe your use case is different, but for me it seems like you're missing the forest for the trees.

> benefits of a statically typed language on a large team

I mean yeah, sure, if you have to work on a large team in the browser/node you're going to have to make tradeoffs for that, and using TS seems like it'll help everyone go home at 5. I don't think I'm missing the forest for the trees, we're talking past each-other.

To illustrate a bit further, while I like Rust a lot, (the problems it tackles are MUCH more real than the ones TS does) and I put in the effort to learn and use it on a few personal projects I still find myself reaching for C almost universally these days. Even in the case of Rust's very useful tradeoffs I feel like they cost too much of my freedom, and TS' guarantees are much more surface level for a similar cost.

Re: Tricks I wish I knew when I learned TypeScript

#212

Earlier quoted context omitted.

> 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 know dozens of people who tried understanding Promises and all of them succeeded. I know dozens of people who tried to understand monads (including myself) and maybe 3 of them succeeded (I do not consider myself one of them).

Not arguing for or againts something, this is just something I wanted to say.

Framing matters here, the API of Promises in js maps almost nicely to the common monad API of bind (then), join (implicitely done by the runtime whenever possible), and return (Promise.resolve). Learning any monads is unlikely to be harder than this as these operations are indeed quite intuitive.

What is often referenced with learning monads is instead Learning All the Monads, sometimes adding a touch of Learning All the Monad Transformers and interactions of different monads. This intrinsecally needs to be done in a generic/parametric way and is way harder.

To my knowledge Haskell is the most mainstream[1] language only typed language that allows expressing the categorical definition, most other type systems are significantly more limited in how much maths/category theory they can express and often focus on specialized functionality with practical implication like Rust's ownership system or Typescript's Capitalize that only exists to allow nicer typing of some common API desings[2]

[1] most mainstream typed language at least, you can implement Monad is JS/TS but the language cannot express it the same way C cannor express generics even if you can manually implement them in it.

[2] https://www.typescriptlang.org/docs/handbook/utility-types.h...

Re: Tricks I wish I knew when I learned TypeScript

#213
post #202

Earlier quoted context omitted.

I don't think there are no use cases, but I think they are rarer than people think, and that for the most of development TS will be picked because it's someone preference not because of its actual benefits.

Do you really think that use cases for statically typed languages are rare?

TS =/= statically typed languages

Static typing can be a very useful tool especially when the language is designed around it, in TS it is a painful kludge.

Re: Tricks I wish I knew when I learned TypeScript

#214

Earlier quoted context omitted.

void implies that the return type should is undefined behavior and should not be relied upon, so that something like this const x = foo(); is incorrect when foo() returns void. 99% of the time x will be undefined (the value) but there are cases where it would not be. For example arr.forEach(x => x.sort()) sort returns a value as well as having a side effect. But forEach expects a void callback. This code is perfectly…

I agree. I don't see where what you wrote contradicts what I said.

Perhaps they were not trying to contradict you?

Re: Tricks I wish I knew when I learned TypeScript

#215

Earlier quoted context omitted.

> 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 know dozens of people who tried understanding Promises and all of them succeeded. I know dozens of people who tried to understand monads (including myself) and maybe 3 of them succeeded (I do not consider myself one of them).

Monads and Promises are not comparable. The IO Monad fulfills a similar role to Promises and people learning Haskell grasp them immediately. Haskell also has an equivalent of the async/await syntax called the do notation which makes things nice and easy to read.

You don't really need to understand monads to understand the IO monad or Promises. If you want to understand monads, look at their signature, mainly the bind operator and try to implement something with it. A logger, a list, the IO monad itself. It's not that hard, it's just that nobody bothers playing with it and just try to learn the theory without experimenting with monads in code. After a few tests you'll build an intuition for it and you'll get why they call them programmable semicolons.

Monads is just one of the abstractions that can be used to implement IO in Haskell btw, it was just the authors flexing their category theory that got us in this situation.

At the same time, one of the reasons I learned Haskell is that it had a reputation for being hard and, boy, am I grateful for it.

Re: Tricks I wish I knew when I learned TypeScript

#216

Earlier quoted context omitted.

I know dozens of people who tried understanding Promises and all of them succeeded. I know dozens of people who tried to understand monads (including myself) and maybe 3 of them succeeded (I do not consider myself one of them).

Basically, think of a monad as a Promise. Rather, a Promise is more-or-less an example of a monad. (Yes, I know that due to some technicalities it isn't, but it behaves like one for the purposes of this comment) Mapping a monad is equivalent to Promise#then - if there's a value in the monad, then it calls the function you passed to map and returns the result wrapped in a monad. If there isn't a value in the monad, th…

While we are here, Futures from fantasy land (in js) are better promises because they don't execute immediately and they need to be run manually

Re: Tricks I wish I knew when I learned TypeScript

#217
post #198

Earlier quoted context omitted.

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.

To understand Monads, we have to first understand Functors, Monoids and the Applicative type classes (type classes are more or less the same as interfaces in Java, C++ and the like). A Functor is something that implements a `map` function. You can think of a Functor as anything that can encapsulate/surround something else. The map function applies a function to the encapsulated element without modifying the outer str…

Continue

We are almost there! Let’s tackle Applicative now. What can we do if not only are data is encapsulated in some structure, but even our function which we want to apply to?

Can we apply a list of functions over a list of values? Or an Optional/Result function over an Optional/Result value? Does it even make sense?

Let’s define Applicative as being a Functor that has a `pure` function similar to our Monoid, as well as a `sequentialApplication` one that we will shorten as the cryptix >. Since it is a Functor, remember that it also has a map function available.

The pure function simply encapsulates a type inside itself. For example, a list constructor is precisely that, like python’s list(2, 3) creating a new list. The > is a bit more complex, it takes as parameter a function that is encapsulated in this very type and operates on type A. Its second parameter is an encapsulated object containing type A. And the important thing comes here: it will apply the encapsulated function to an encapsulated data, without unwrapping first.

Let’s say, I have a text field where the user Maybe entered his/her name (sorry) and a field where we await an age. We’ll store these inside a Result and a Result type.

Let’s say we have a User constructor that awaits a name and an age. We could handle each parameter separately here, but what if we have 20? So we instead do something like pure(createUser) > nameResult > ageResult. This magic line will apply the Just createUser function (that is, wrapped into a Result with an existing value due to pure) to a possibly missing name. Let’s stop for a moment here and talk about currying. In many FP languages, calling a function with less parameters is not a compile time error. It gives back a new function that awaits one less parameter. Eg `+ 3` is a lambda that got its first parameter as 3, and will “execute” when we give it the second parameter.

Knowing this, our evaluation so far will be something like Just (createUser(nameResult if it has a value)) or Nothing. Now we apply this, yet again enwrapped function to the last parameter, so we will get as a resulting type a Result, which will contain a user when both values were sent, and will be Nothing if any of them were absent - cool isn’t it?

But I know, we are here for Monads!

Well, Monads are just monoids in the category of endofunctors. Just kidding. They are Applicatices, that also have a `bind` method.

So you’ve seen how we could “sequentially apply” functions. But the “problem” with Applicatives, is that we can’t depend on the output of a previous function — in the previous example we could not have ageResult’s evaluation change depending on what was returned previously. Let’s see another Applicative, the often misunderstood IO.

putStrLn has the following type: String -> IO ().

That is, it waits a string and gives back an IO structure that returns void (actually it is called Unit). If we were to somehow execute it, it would print that string ending with a newline. If we do

(x => putStrLn(“world”)) putStrLn(“hello”), it will output (if we know how to execute it) hello world in two lines. The reason for this strange ordering is, that we apply a function that drops its first parameter to the second one. (Haskell does have a shorthand for this!)

But how can I act upon the result of a previous computation in a “sequential application”, eg. read in a line and print hello $name? By `bind`! It does the following: it needs a monad at hand, with encapsulated type A (eg. IO String for the readline we will use), a function that takes that type A (String) and returns this monad with any type (we will print out the string so we will use putStrLn)

So, bind(getline, name => putStrLn(“hello $name”)) will do what we want and you have just used your first proper Monad (Haskell of course provides a nice syntactic sugar over this called do notations)

With these abstract structures, IO can be dynamically constructed and side effects will only happen where we expect them.

Re: Tricks I wish I knew when I learned TypeScript

#218
post #212

Earlier quoted context omitted.

I know dozens of people who tried understanding Promises and all of them succeeded. I know dozens of people who tried to understand monads (including myself) and maybe 3 of them succeeded (I do not consider myself one of them).

Not arguing for or againts something, this is just something I wanted to say. Framing matters here, the API of Promises in js maps almost nicely to the common monad API of bind (then), join (implicitely done by the runtime whenever possible), and return (Promise.resolve). Learning any monads is unlikely to be harder than this as these operations are indeed quite intuitive. What is often referenced with learning monad…

Otherwise agree with you, just noting that Scala is likely even more mainstream than Haskell and has proper Monads.

Re: Tricks I wish I knew when I learned TypeScript

#219

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…

C is not "barely typed". It has quite a lot of type checking. An expression like "obj.memb" in C requires obj to be declared to have a type which has a member "memb". C catches it if you call a function with the wrong number of parameters, or wrongly typed parameters, such as passing a "struct foo *" pointer where a "struct bar *" argument is required. C has "holes" in the static safety net in areas like memory safet…

C is a statically, but weakly typed language with very few compile time checks and many non-intuitive automatic casts.

Re: Tricks I wish I knew when I learned TypeScript

#220

Earlier quoted context omitted.

Wow, thanks for this. I wasn't even aware of these. I'm surprised I rarely see these in courses/tutorial. These should be like day 1 material.

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.

I don't have it handy but with template literal types I was able to have a type of "stripped strings" (that is, strings without leading or trailing whitespace) that seemed surprisingly usable - string literals would match (or not, as appropriate) with no boilerplate, while dynamic strings would need to be fed to a cleaning function.

I never put it in production, partially because of concerns over maintainability but far more because I had no need for it.

Post reply on HN