Live data from Hacker News

TypeScript: Branded Types

prosopo.io

41–50 of 209 posts

Re: TypeScript: Branded Types

#42

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.

Re: TypeScript: Branded Types

#43

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

FWIW, classes in TypeScript become nominal types when they have a non-public member. But I definitely do feel real FOMO over Flow’s opaque types.

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.

Re: TypeScript: Branded Types

#45

Earlier quoted context omitted.

Yeah in TS' own playground example they don't create a Symbol, they just intersect it inline: https://www.typescriptlang.org/play#example/nominal-typing

Nice. I don't love that example though, because the brand field's value of a string literal will make it seem like the object actually has a property named `__brand` when it doesn't. `never` is the best brand field type as far as I can tell.

`never` is a problematic field type, at least unless you make efforts (via non-exported symbols, for instance) to make sure the field is inaccessible - `never` is the type of a value that doesn't exist; it's there in the type system to signify an impossible scenario. For instance, a common use-case is to mark the type of a variable after type narrowing has exhausted every possible case.

If you assert that your id's actually do have a never-typed field, and you let your program access it, you're basically letting users enter an impossible state freely and easily.

Re: TypeScript: Branded Types

#46

It's a clever trick, but the compiler errors leave a lot to be desired. If a TS library makes heavy use of nominal (branded/distinct) types in a domain where accidentally passing values of the wrong type is common, I can imagine a lot of library users being more confused, not less, by code that uses this approach. The article reads more like an endorsement of languages that do structurally-aware nominal typing (that…

I’ve found TypeScript errors can be made a lot easier to understand with some forethought about how invalid types are defined in the first place. For instance, a many-branched conditional type may be much easier to understand (both as a library user and as a reviewer/maintainer of the library code itself) if each `never` (or whatever actual failure case) is instead a string literal describing the nature of the failure. And better still if it can be templated with an aspect of the input type to highlight what aspect of it triggered the error.

Re: TypeScript: Branded Types

#47

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…

do you need readonly with never?

Re: TypeScript: Branded Types

#48

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

> adhering to liskov substitution principles

what does this even mean?

> And has 10x less LoC than ts

Prolly b/c Flow isn't able to express the advanced types (albeit with 10x LoC) in the first place.

Re: TypeScript: Branded Types

#49

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.

If we needed a special Typescript runtime to use Typescript it would become nearly useless. The vast majority of Typescript becomes JavaScript running in Node or V8.

The web is stuck with JavaScript, and Typescript is a tool to help us write maintainable JavaScript.

Re: TypeScript: Branded Types

#50
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?

Not necessarily wrong. You’re probably doing the same work at runtime. That might be either just as good (a subjective preference) or more correct (for certain kinds of dynamism) depending on context. In some cases, there are clear static invariants that could be guaranteed at compile time, and some folks will be more inclined to squeeze as much out of that as possible. In my experience, the benefits of that vary wildly from “total waste of time” to “solves a recurring and expensive problem for good”, with a lot in between.
Post reply on HN