Live data from Hacker News

TypeScript: Branded Types

prosopo.io

91–100 of 209 posts

Re: TypeScript: Branded Types

#92
post #90

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 is dead (for jobs). I'm gonna annihilate Dart (apart from jobs)

java is great for jobs as well.

Re: TypeScript: Branded Types

#93

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.

That's a weird objection, because Typescript classes are literally Javascript classes[1].

[1]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...

Re: TypeScript: Branded Types

#94

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] […

Tried Flow first, back in the day. I was ready to give up the whole idea as not-at-all-worth-the-trouble if Typescript had been as mediocre an experience. Fortunately it wasn’t and now I get to not-hate working in JavaScript.

Yes there was a time when atom/vscode integration was shit.

They also fucked up typings in terms of community management.

Those two alone probably put them into downward spiral.

But the language is being developed with activity stronger than ever.

And it is well designed and pleasure to code in.

Re: TypeScript: Branded Types

#95
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.

> If this is something you need, it smells like "runtime checking" not amending the type system. This is both! The primary point of branded types is to allow you to use the type system to ensure that a particular runtime check has taken place.

> The primary point of branded types is to allow you to use the type system to ensure that a particular runtime check has taken place.

I see. This is kind of cool, though the branding can still be broken via down-the-stream mutations. Would be nice to enforce re-branding every time a variable is changed, but that seems like a lot of overhead.

Re: TypeScript: Branded Types

#96
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…

> Unless you control API usage from end-to-end (which kind of defeats the point of an API)

Isn't this all frontend client bundles that talk to their own private backend API? Those are controlled end-to-end. My company has one, yours probably does too!

Re: TypeScript: Branded Types

#97
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.

> And runtime checking is ... suboptimal.

Especially on the frontend, where your `throw new Error("Bad input type")` might brick the entire app if uncaught. I'd much rather hear an earful from TypeScript before a bundle is ever produced.

Re: TypeScript: Branded Types

#98

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)?

If you have a distance argument typed as a number, for example, and you pass miles instead of km.

It is equivalent to newtype in haskell.

Another example somebody mentioned here is a logged in user. A function can take a user and we need to always check that the user is logged. Or we could simply create a LoggedUser type and the compiler will complain if we forget.

Re: TypeScript: Branded Types

#99
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.

That’s nothing specific to branded types. We know Typescript doesn’t enforce anything at runtime, whether it’s primitive types, complex types, nullability or anything else, that’s nothing new.

It’s not about security, it’s about safety: make it harder to do the wrong thing, and make it easier to do the right thing than the wrong one.

Re: TypeScript: Branded Types

#100

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.

> Other statically typed languages retain type information at runtime.

Funnily enough, Haskell[0] doesn't... unless you ask it to by explicitly asking for it via Typable[1].

[0] ... which is renowned/infamous for its extremely static+strong typing discipline. It is nice that one can opt in via Typeable, but it's very rare to actually need it.

[1] https://hackage.haskell.org/package/base-4.19.1.0/docs/Data-...

Post reply on HN