Live data from Hacker News

Branded types for TypeScript

carlos-menezes.com

71–80 of 152 posts

Re: Branded types for TypeScript

#71
I like to make the 'brand' property optional so that it doesn't actually have to be there at runtime, but the TypeScript type-checker will still catch mismatches

  type USDollars = number & { currency?: "USD" }
(or something like that; My TypeScript-fu may be slightly rusty at the moment.)

Of course a `number` won't have a currency property, but if it did, its value would be "USD"!

I've found that TypeScript's structural typing system fits my brain really well, because most of the time it is what I want, and when I really want to discriminate based on something more abstract, I can use the above trick[1], and voila, effectively nominal types!

[1] With or without the tag being there at runtime, depending on the situation, and actually I do have a lot of interface definitions that start with "classRef: " + some URI identifying the concept represented by this type. It's a URI because I like to think of everything as if I were describing it with RDF, you see.

(More of my own blathering on the subject from a few years ago here: http://www.nuke24.net/plog/32.html)

Re: Branded types for TypeScript

#72
Pascal worked that way all the time, and it was hated. You could have "inch" and "meter" version of integer, and they were not interchangeable. This was sometimes called "strong typing"

It's interesting that in Rust, "type" does not work that way. I kind of expected that it would. But no, "type" in Rust is just an alternate name, like "typedef" in C.

Re: Branded types for TypeScript

#73
post #58

Earlier quoted context omitted.

I see where you are coming from but you are not quite understanding what the OP was saying class A { public value: number } class B { public value: number } const x: A = new B() // no error This is structural typing (shape defines type), if typescript had nominal typing (name defines type) this would give an error. You could brand these classes to forcefully cause this to error. Branding makes structural typing work…

> Branding makes structural typing work like nominal typing for the branded type only. That's not quite true. Branding doesn't exist at run time, where as nominal typing usually does at some level. Classes exist at runtime, but most typescript types don't, so unless there's something specific about the shape of the data that you can check with a type guard, it's impossible to narrow the type.

> Classes exist at runtime

Not necessarily, depending on the language. Functional languages and system languages such as OCaml, Haskell, Rust, but also C (painfully) and C++ can represent wrapper types within a nominal type system at no runtime cost.

Re: Branded types for TypeScript

#74
post #21

It took me so long to fully appreciate TypeScript's design decision for doing structural typing vs. nominal typing. In all scenarios, including the "issue" highlighted in this article there is no reason for wanting nominal typing. In this case where the wrong order of parameters was the issue, you can solve it with [Template Literal Types]( https://www.typescriptlang.org/docs/handbook/2/template-lite... ). See [1]. A…

This example is also an odd choice because... it's not the right way to do it. If you're super concerned about people misusing hashes, using string as the type is a WTF in itself. Strings are unstructured data, the widest possible value type, essentially "any" for values that can be represented. Hashes aren't even strings anyway, they're numbers that can be represented as a string in base-whatever. Of course any such…

This is a bit of a nitpick because strings often aren't the most appropriate type for hashes... but in some cases I can see using strings as the best choice. It's probably the fastest option for one.

In any case it still demonstrates the usefulness of branded types.

Re: Branded types for TypeScript

#75
post #38
post #21

It took me so long to fully appreciate TypeScript's design decision for doing structural typing vs. nominal typing. In all scenarios, including the "issue" highlighted in this article there is no reason for wanting nominal typing. In this case where the wrong order of parameters was the issue, you can solve it with [Template Literal Types]( https://www.typescriptlang.org/docs/handbook/2/template-lite... ). See [1]. A…

> A runtime bug is now a compile time bug. This isn't valuable to you? How do you get this without nominal typing, especially of primatives?

Did they edit their post? The > syntax indicates a verbatim quote here.

Re: Branded types for TypeScript

#79
post #31
post #3

In most languages, doing what this article describes is quite straightforward: you would just define a new type (/ struct / class) called ‘Hash’, which functions can take or return. The language automatically treats this as a completely new type. This is called ‘nominal typing’: type equality is based on the name of the type. The complication with TypeScript is that it doesn’t have nominal typing. Instead, it has ‘st…

Typescript has good reasons to default to Structural Typing as untagged union type are one of the most used types in typing js code and Nominal Typing does not really have a good equivalent for them.

Nominal typing with correct variance describes OO (classes, inheritance and rules governing it >). Structural typing is used for everything else in js.

Flow does it correctly. Typescript treats everything as structurally typed.

As a side note flow also has first class support for opaque types so no need to resort to branding hacks.

Re: Branded types for TypeScript

#80
post #72

Pascal worked that way all the time, and it was hated. You could have "inch" and "meter" version of integer, and they were not interchangeable. This was sometimes called "strong typing" It's interesting that in Rust, "type" does not work that way. I kind of expected that it would. But no, "type" in Rust is just an alternate name, like "typedef" in C.

NASA might have some thoughts on mixing inch and meter types :-)

https://en.wikipedia.org/wiki/Mars_Climate_Orbiter

Post reply on HN