Live data from Hacker News

TypeScript: Branded Types

prosopo.io

71–80 of 209 posts

Re: TypeScript: Branded Types

#71
post #67

Ah, the magical disappearing type system - now being used for nominal typing. I'm curious to see what the JS code looks like for casts and type checks in that case.

> Ah, the magical disappearing type system - now being used for nominal typing.

More like: magical disappearing type system is not nominal: hacky workarounds ensue.

Re: TypeScript: Branded Types

#72

Earlier quoted context omitted.

I don't see why. I greatly prefer typescript's structural typing for almost everything. But id's in data models are an exception, so I use branding for those. It works perfectly, the only overhead is in the write-once declaration and now I am protected from accidentally using an AccountId where a MemberId was expected, even though they are both just strings.

How do ids of different types accidentally get into a place they shouldn't be? Is this simply a case where someone mistakenly passes along a property that happens to be called "id", not noticing it's an account id rather than a member id (as in, an implementation error)?

This kind of mistake is quite easy to make, especially when somebody writes a function that takes several IDs as arguments next to each other. I've seen it happen a number of times over the years

Re: TypeScript: Branded Types

#73

I can see this being useful and it seems about as neat a solution as you can currently get in TypeScript as it stands today, but it’s still cumbersome. My feeling is that while you can do this, you’re swimming upstream as the language is working against you. Reaching for such a solution should probably be avoided as much as possible.

Rather, I think Typescript's philosophy of not having a runtime is simply wrong. Other statically typed languages retain type information at runtime. I don't understand why that was so important to explicitly exclude from Typescript.

I disagree. If we had a runtime we'd have to inject that all over the place and compatibility with javascript wouldn't be a given.

Re: TypeScript: Branded Types

#75
post #54

Weird idea, as types in TS are structural by design . If this is something you need, it smells like "runtime checking" not amending the type system.

Design doesn’t cover all use cases. There’s nothing weird about wanting different types for “user id” and “organisation id” so that you don’t use the wrong argument by mistake

While you're right that branding makes passing arguments more ergonomic, I will still always be able to do `as OrgId` or `as UserId` so you need to do have some failure handling anyway, unless you're okay with blowing up in the user's face.

Re: TypeScript: Branded Types

#77
post #75

Earlier quoted context omitted.

Design doesn’t cover all use cases. There’s nothing weird about wanting different types for “user id” and “organisation id” so that you don’t use the wrong argument by mistake

While you're right that branding makes passing arguments more ergonomic, I will still always be able to do `as OrgId` or `as UserId` so you need to do have some failure handling anyway, unless you're okay with blowing up in the user's face.

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 ways that would require handling failures?

Re: TypeScript: Branded Types

#78
post #54

Weird idea, as types in TS are structural by design . If this is something you need, it smells like "runtime checking" not amending the type system.

Right, but there are times when structural typing is not the right choice. And runtime checking is ... suboptimal. I mean, saying runtime checking is the right choice is like saying a type system isn't necessary, because you have automated tests. They're great, and they're a tool that provides value... but so too are types.

Re: TypeScript: Branded Types

#79
Anytime I’ve come across the need to do this, I’ve found a class is a better and less complicated solution.

I really like the pattern of value objects from Domain Driven Design. Create a class that stores the value, for example email address.

In the class constructor, take a string and validate it. Then anywhere that you need a valid email address, have it accept an instance of the Email class.

As far as I understand classes are the only real way to get nominal typing in TypeScript.

Re: TypeScript: Branded Types

#80

Earlier quoted context omitted.

Yes, ts is full of this kind kind of adhoc-ifs-like glued together, also exactness check only when it's literal object etc. Flow is more principled.

I mean. I think this specific case is a lot more principled than you seem to think. It’s certainly well reasoned from a perspective of structural typing by default.

Yes, they have their reasons. They always do, tradeoff etc, I know.

It doesn't change the fact that ie. adding private member is breaking change in your library which is kind of funny (until it's not funny of course).

Also stuff like:

    class Foo { private foo = 1 }
    class Bar {}
    const a: Bar = new Foo
...typechecks so that's it for nominality.

It's all ifs all the way down.

Post reply on HN