Live data from Hacker News

TypeScript: Branded Types

prosopo.io

141–150 of 209 posts

Re: TypeScript: Branded Types

#141

To me the real benefit of branded types is for branded primitives. That helps you prevent mixing up things that are represented by the same primitive type, like say relative and absolute paths, or different types of IDs. You really don't need the symbol - you can use an obscure name for the branding field. I think it helps the type self-document in errors and hover-overs if you use a descriptive name. I use branding…

Is all Typescript unreadable, or is that just your style?

Re: TypeScript: Branded Types

#142
post #141

To me the real benefit of branded types is for branded primitives. That helps you prevent mixing up things that are represented by the same primitive type, like say relative and absolute paths, or different types of IDs. You really don't need the symbol - you can use an obscure name for the branding field. I think it helps the type self-document in errors and hover-overs if you use a descriptive name. I use branding…

Is all Typescript unreadable, or is that just your style?

It’s very readable to me, and is much cleaner than the notation in the article.

Is your problem the line wraps in the parent’s comment?

Re: TypeScript: Branded Types

#143
post #132

Earlier quoted context omitted.

You can google, gpt or look at wikipedia for "liskov substitution principles". It's related to object oriented programming, more specifically to inheritance and what is allowed as substitution as superclass vs subclass depending on which position it sits in argument vs return value. It's very interesting read if you don't know about it and you're using OOP. What advanced types do you have in mind? ps. the way you're…

I know what SOLID is, questioning how exactly you think Flow has "liskov substitution" as a feature.

L in SOLID refers to Liskov substitution principles.

It's the only one from the SOLID list which can be typechecked - others are design principles.

"Flow adhering to it" means that violating code will be flagged by type system.

It matters because unlike other principles, violations can cause runtime errors.

Re: TypeScript: Branded Types

#144

Earlier quoted context omitted.

Classes can also make use of the native `instanceof` JavaScript operator [0]. It is also possible to then infer a type from a class so you can use both the class where you want to discriminate types and the type where you really only care about the shape. The absolutism towards OOP/FP -- instead of embracing the right use cases for each -- always ruffles me in the wrong way. C#, for example, does a great job of blend…

Classes are very underutilised in TypeScript. I recently introduced them to our codebase at my day job and got a fair bit of pushback because it wasn’t “JavaScripty” enough.

I like classes well enough; I just find that often they over-complicate simple code, especially when you introduce inheritance. Since classes are effectively just syntax sugar I often find it's more intuitive to go with object syntax but to each their own. So long functionality is isolated in modules I'm happy.

Re: TypeScript: Branded Types

#145
post #2

Amazing, we have invented nominal typing in a structural typing system. Sometimes I wonder what kind of programs are written using all these complicated TS types. Anecdotally, we use very simple, basic types in our codebase. The need for tricks like this (and other complicated types) is simply not there. Are we doing something wrong?

> The need for tricks like this (and other complicated types) is simply not there.

It just depends on how constrained by types you want your code to be and how much time and effort you're willing to spend maintaining and writing code that fits within those constraints.

Sometimes complicated types are introduced because you want to maintain editor features such as find by reference and the ability to refactor later. When it works, removing or adding new features feels fast, easy and safe.

In the articles case you could differentiate between an email string type and a user id string type. Maybe sometime in the future you want to change the id to an integer instead, so now that it's already distinguished you could find all those places where that's applied.

That's at least a selling point, in practice I've used this a few times but it doesn't come up that often. Sometimes the blast radius of a type isn't big so it's not worth doing.

Re: TypeScript: Branded Types

#146

Flow is much better with opaque types. Also nominal types for classes. And correct variance. And adhering to liskov substitution principles. And exact object types. And spread on types matching runtime behavior. And proper no transpilation mode with full access to the language. And has 10x less LoC than ts. ps. before somebody says "flow is dead" have a look at flow contributions [0] vs typescript contributions [1] […

Flow regularly crashed with bizarre segfaults errors, the last time I used it.

Re: TypeScript: Branded Types

#147
post #83

Earlier quoted context omitted.

The way you're describing it sounds to me like you are adding failure handling to handle cases where the programmer is intentionally misusing the thing. I would argue that in this type of situation, the error handling is not necessary because it would hide the fact that the thing is being misused. Or perhaps I'm misunderstanding your comment. When you do `as OrgId` or `as UserId`, where do you envision those casts in…

My point is that the API consumer does not guarantee types (say it's REST or something), so the assumption that the string you send it will always be the right type (or call it "format") seems like a bad one. Unless you control API usage from end-to-end (which kind of defeats the point of an API), you need error checking (or at least exceptions to bubble up). A lot of times branding is used to mark data received from…

> My point is that the API consumer does not guarantee types (say it's REST or something), so the assumption that the string you send it will always be the right type (or call it "format") seems like a bad one.

The raw data from the API will not have any of your internal types applied to it yet, it'll be raw bytes or typed `string`. So I don't really see the connection between this and "I will still always be able to do `as OrgId` or `as UserId` so you need to do have some failure handling". Only your own trusted code can do "as OrgId", so... don't do that unless you have an OrgId. And once your own trusted code has made an OrgId, you don't need any runtime checking to see if it actually is an OrgId.

> A lot of times branding is used to mark data received from a database, e.g.: this field is an `OrgId`, but I can do all kinds of things to that string which might make it not-an-`OrgId` at any point.

What kind of things? Strings aren't mutable so you must be making a new string. But a new string will have a type like `string`, not `OrgId`, and then using it as an OrgId won't compile.

Re: TypeScript: Branded Types

#148

Flow is much better with opaque types. Also nominal types for classes. And correct variance. And adhering to liskov substitution principles. And exact object types. And spread on types matching runtime behavior. And proper no transpilation mode with full access to the language. And has 10x less LoC than ts. ps. before somebody says "flow is dead" have a look at flow contributions [0] vs typescript contributions [1] […

Check out the react codebase, which is presumably the flagship use of flow. It has hundreds of FLOW FIXME annotations. It's easier have a lot of features and small code base if the you don't handle the difficult cases.

It's the other way around.

Handling difficult cases leads to more type errors.

If type system is lax, it won't flag them but they can fail at runtime.

React has very little of $FlowFixMe annotations for its codebase.

In typescript projects on the other hand it's normal to see unsafety as normal code (casting, non null assertions, implicit and explicit anys etc).

Re: TypeScript: Branded Types

#149

An example of what you can implement on top of branded types that I want to share with fellow hackers: - currencies You may have some sort of integer representing the number of cents of some currency and you want to avoid doing operations between the wrong currencies (such as adding euros and pesos). You can create branded types and functions that work on those Euro branded numbers and then decide how to do math on i…

Another example: inches versus meters. We have lost a mars probe due to a misinterpretation of the numbers: https://www.latimes.com/archives/la-xpm-1999-oct-01-mn-17288...

Re: TypeScript: Branded Types

#150
post #133

Earlier quoted context omitted.

Yes, otherwise consumers could try reading the property (that doesn’t exist).

how would read only fixes consumers read ing the property?

it doesn't. never prevents reading and readonly prevents (over)writing.

GP just focused on the never-part of your question.

Post reply on HN