Live data from Hacker News

Learn how to unleash the full potential of the type system of TypeScript

type-level-typescript.com

161–170 of 256 posts

Re: Learn how to unleash the full potential of the type system of TypeScript

#161

I currently have to occasionally contribute to a TypeScript codebase at work. I appreciate how much better it is than Javascript. When I write code as an outsider (Java and Go developer), I feel like I use the type system in sensible and readable ways. When I look at the code written by the native TypeScript experts in my company it is a bewildering, abstract, unreadable morass. I have no idea what's going on half th…

Yeah, what a terrible syntax :( Just today I was looking at the type definition for a third-party lib (ramda)... what the heck does this even mean... compose (fn5: (x: T5) => T6, fn4: (x: T4) => T5, fn3: (x: T3) => T4, fn2: (x: T2) => T3, fn1: (x: T1) => T2, fn0: (x0: V0, x1: V1, x2: V2) => T1): (x0: V0, x1: V1, x2: V2) => T6; Got it?

compose is a higher order function. In the first step it accepts a function that converts 3 values (V1 to V3) into a single values (T1) and a series of conversion functions that converts this single value into another value (T1 into T2, T2 into T3 and so on until T6). Using these functions it produces a new function that converts the combination of V1, V2 and V3 into a T6.

I don't know ramda, but I assume this is only part of the type definition of compose and this is just the longest part of it. I think compose is written in such a way that it can accept a many conversion functions as you want and this is just the longest variant that is encoded in the types.

Re: Learn how to unleash the full potential of the type system of TypeScript

#162

A great idea. Now, everyone that learns this stuff, show some restraint! The drawback of a powerful type system is you can very easily get yourself into a type complexity mudhole. Nothing worse than trying to call a method where a simple `Foo` object would do but instead you've defined 60 character definition of `Foo` capabilities in the type system in the method signature. Less is more.

If your `Foo` object has 60 potential character definitions... that sounds (smells) like it would be a code smell of something wrong upstream. Perhaps it's time to refactor the function.

Ignoring the 60 different character definitions isn't going to make the problem that you have 60 possible variants go away just because you didn't type it.

Re: Learn how to unleash the full potential of the type system of TypeScript

#163

A great idea. Now, everyone that learns this stuff, show some restraint! The drawback of a powerful type system is you can very easily get yourself into a type complexity mudhole. Nothing worse than trying to call a method where a simple `Foo` object would do but instead you've defined 60 character definition of `Foo` capabilities in the type system in the method signature. Less is more.

My coding philosophy is centered around simple interfaces. I think of power sockets and plugs. The simpler the socket/plug design, the easier it is to plug in. It's easier to connect a European plug which has 2 round pins than it is to connect a UK plug which has 3 rectangular pins at different angles. You can imagine how difficult it would be to connect a plug with 10 pins; it would be difficult to get the alignment…

> It's easier to connect a European plug which has 2 round pins than it is to connect a UK plug which has 3 rectangular pins at different angles.

Speaking strictly on plugs - while I agree it is simpler/easier - I disagree that EU plug is better.

For the bulk and lack of directionality - significantly safer (pin lengths, shielded to tip), requires a ground pin even if dummy, carries 13A easy!

The safety aspects are incredible[0]. I do not worry about my small children at all.

Lived in HK where the EU (China) and UK (HK) are pretty common in one household.

[0] https://www.youtube.com/watch?v=UEfP1OKKz_Q

Re: Learn how to unleash the full potential of the type system of TypeScript

#164

A great idea. Now, everyone that learns this stuff, show some restraint! The drawback of a powerful type system is you can very easily get yourself into a type complexity mudhole. Nothing worse than trying to call a method where a simple `Foo` object would do but instead you've defined 60 character definition of `Foo` capabilities in the type system in the method signature. Less is more.

My coding philosophy is centered around simple interfaces. I think of power sockets and plugs. The simpler the socket/plug design, the easier it is to plug in. It's easier to connect a European plug which has 2 round pins than it is to connect a UK plug which has 3 rectangular pins at different angles. You can imagine how difficult it would be to connect a plug with 10 pins; it would be difficult to get the alignment…

The thing with electrical plus is that they should be designed around safety first, rather than convenience. And the U.K. plug is a lot more safety focused than many other plug standards.

The advantage of the U.K. plug is that live pins are physically blocked and only released when the Earth pin is present. This is why the Earth pin is slightly longer on U.K. plugs and why insulated devices have a plastic Earth pin rather than no pin at all. The advantage of this is so you cannot jam things into them (either accidentally or intentionally) without the Earth pin. Thus making the plug much safer.

I’ve found U.K. plugs to be much more secure inside the socket too. US plugs often come away from the wall when there is a little bit of weight or tension on the plug. U.K. plugs require a great deal more pressure to come loose from the socket.

If I were to bring this back to types I’d say one needs to evaluate what the requirements are: safety or convenience.

Re: Learn how to unleash the full potential of the type system of TypeScript

#165

Earlier quoted context omitted.

It's very simple to understand. You don't have to actually read the definition just know what "compose" does at a high level.

What compose() does is not the point here, it's that the type definition is totally unreadable. I was trying to figure out what compose was supposed to return (the function or the value), in that case, and I still don't really know. Another random example from Axios: (onFulfilled?: (value: V) => T | Promise , onRejected?: (error: any) => any): number; Or eslint: type Prepend = ((_: Addend, ..._1: Tuple) => any) exten…

> I was trying to figure out what compose was supposed to return (the function or the value), in that case, and I still don't really know.

It returns a function. The one that's equivalent to applying the arguments in reverse order. I think that this signature is pretty clear for anyone experienced with a statically typed language with generics and higher order functions.

On the other hand, I have no idea why a compose function that takes exactly 6 arguments, the last of which is function which takes 3 arguments would be a desirable abstraction. But I don't think static typing is necessarily to blame for this -- this just looks like a clunky function that has a clunky type.

I'm fully with you on the second example though.

Re: Learn how to unleash the full potential of the type system of TypeScript

#166

Earlier quoted context omitted.

Yeah, what a terrible syntax :( Just today I was looking at the type definition for a third-party lib (ramda)... what the heck does this even mean... compose (fn5: (x: T5) => T6, fn4: (x: T4) => T5, fn3: (x: T3) => T4, fn2: (x: T2) => T3, fn1: (x: T1) => T2, fn0: (x0: V0, x1: V1, x2: V2) => T1): (x0: V0, x1: V1, x2: V2) => T6; Got it?

compose is a higher order function. In the first step it accepts a function that converts 3 values (V1 to V3) into a single values (T1) and a series of conversion functions that converts this single value into another value (T1 into T2, T2 into T3 and so on until T6). Using these functions it produces a new function that converts the combination of V1, V2 and V3 into a T6. I don't know ramda, but I assume this is onl…

Yes, that's correct... compose() pipes a bunch of passed functions from right to left. Here's the actual type definition if you want to see: https://github.com/googol/DefinitelyTyped/blob/6836f798cb186...

But even at its simplest variant, with just one or two functions passed, what the V0 or T1 do is pretty confusing. I thiiiiiiiiink it's trying to ensure the return type of one function is correctly passed as the input type of the subsequent function, and so on and so forth, but I don't really know.

Also, I should note that I'm using an older version of that lib. The latest version has cleaner typings... still difficult, but at least formatted better: https://github.com/DefinitelyTyped/DefinitelyTyped/blob/mast...

Re: Learn how to unleash the full potential of the type system of TypeScript

#167

> Over the years, the type system of TypeScript has grown from basic type annotations to a large and complex programming language. Give someone (particularly a developer) the opportunity to build something complicated and undoubtedly they will. So now you have two problems, the complicated program that actually does some hopefully useful work, and another complicated program on top of it that fills your head and slow…

Hard disagree. For me, the proof is in the pudding. When writing regular Javascript, I need to run and debug my code often as I'm developing it to make sure all intermediate states make sense and that there's no edge cases I've missed. With Typescript I can often write code for hours without even starting it up, and when I finally do run it, it usually works correctly right out of the box.

I don't know why it took so long to really take off. I've been using TypeScript since almost day one for these same reasons.

Maybe it's because I came from C++.

Like in C++, I like the flexibility of not being too under-typed (impossible to not break anything) or over-typed (impossible to do anything).

Re: Learn how to unleash the full potential of the type system of TypeScript

#168

A great idea. Now, everyone that learns this stuff, show some restraint! The drawback of a powerful type system is you can very easily get yourself into a type complexity mudhole. Nothing worse than trying to call a method where a simple `Foo` object would do but instead you've defined 60 character definition of `Foo` capabilities in the type system in the method signature. Less is more.

The types in your code are just as designed just like any other aspect of it. It's not a matter of restraint, it's a matter of doing things on the correct way.

What's 'correct' from your point of view (as library implementer) may be 'overly complex and a hassle to use' from the library user's pov though.

Re: Learn how to unleash the full potential of the type system of TypeScript

#169
post #165

Earlier quoted context omitted.

What compose() does is not the point here, it's that the type definition is totally unreadable. I was trying to figure out what compose was supposed to return (the function or the value), in that case, and I still don't really know. Another random example from Axios: (onFulfilled?: (value: V) => T | Promise , onRejected?: (error: any) => any): number; Or eslint: type Prepend = ((_: Addend, ..._1: Tuple) => any) exten…

> I was trying to figure out what compose was supposed to return (the function or the value), in that case, and I still don't really know. It returns a function. The one that's equivalent to applying the arguments in reverse order. I think that this signature is pretty clear for anyone experienced with a statically typed language with generics and higher order functions. On the other hand, I have no idea why a compos…

> I think that this signature is pretty clear for anyone experienced with a statically typed language with generics and higher order functions.

Sounds like I have stuff to study!

Maybe ramda was an extreme example (with or without typescript, it was so hard to read that our dev team decided to just remove it altogether and replace it with more verbose but easier to read vanillaJS code or equivalent lodash functions). But I come across difficult TypeScript examples nearly every day of my work, where I feel like I'm reading an obfuscated leetcode challenge instead of the straightforward business logic in the rest of the codebase.

Once I finally understand a complex type, my usual reaction is, "That's it? That's all that was trying to express?" It's just an arcane syntax to me. Sounds like learning about generics and higher-order functions in statically typed languages would be a good starting place... thanks!

Re: Learn how to unleash the full potential of the type system of TypeScript

#170

> Over the years, the type system of TypeScript has grown from basic type annotations to a large and complex programming language. Give someone (particularly a developer) the opportunity to build something complicated and undoubtedly they will. So now you have two problems, the complicated program that actually does some hopefully useful work, and another complicated program on top of it that fills your head and slow…

Hard disagree. For me, the proof is in the pudding. When writing regular Javascript, I need to run and debug my code often as I'm developing it to make sure all intermediate states make sense and that there's no edge cases I've missed. With Typescript I can often write code for hours without even starting it up, and when I finally do run it, it usually works correctly right out of the box.

The core functionality of Typescript of adding basic type hints to JS is definitely better than writing plain Javascript, but the type system feature set is way beyond it's peak and deep in diminishing returns territory. I realize that this complexity may be required to gradually convert a 'worst case' Javascript code base into 'correct' Typescript, but IMHO most new Typescript code should limit itself to a simple subset of the type system.

I've been coding C++ most of my life, and I must say, TS is starting to look more and more like C++ (which definitely isn't a good thing because it lures programmers into complexity).

Post reply on HN