Live data from Hacker News

Branded types for TypeScript

carlos-menezes.com

11–20 of 152 posts

Re: Branded types for TypeScript

#11

Really ugly way to avoid something already solved by named parameters and/or namespacing

You might need to read the article again, because those things are unrelated. Or you should explain what you mean.

I read the article, thanks.

It makes the claims that (1) a string of a specific form (a hash) could be misused (eg. someone might call toUpper on it) or (2) passed in incorrect order to a function that takes multiple strings.

Named parameters / outward-facing labels (Swift) completely solves (2). For (1), the solution is just ugly. Just use the type system in a normal manner and make a safe class “Hash” that doesn’t allow misuse. And/or use namespacing. And/or use extensions on String. And/or add a compiler extension that looks like outward-facing labels but for return types. So many cleaner options than this nasty brand (yes, that’s the point of the article, but the solution is still hideous. Make it elegant).

Re: Branded types for TypeScript

#12
Flow has actual support for this with opaque types. You just use the opaque keyword in front of a type alias ˋopaque type Hash = string` and then that type can only be constructed in the same file where it is defined. Typescript could introduce a similar feature

Re: Branded types for TypeScript

#13

Earlier quoted context omitted.

> In most languages, doing what this article describes is quite straightforward Well, no. In most languages you wind up making a typed wrapper object/class that holds the primitive. This works fine, you can just do that in TypeScript too. The point of branded types is that you're not introducing a wrapper class and there is no trace of this brand at runtime.

There's never any trace of typescript types at runtime.

If you wrapped the value to give it a “brand”, the wrapper would still exist at runtime. The technique in the article avoids that.

Re: Branded types for TypeScript

#14

Earlier quoted context omitted.

> In most languages, doing what this article describes is quite straightforward Well, no. In most languages you wind up making a typed wrapper object/class that holds the primitive. This works fine, you can just do that in TypeScript too. The point of branded types is that you're not introducing a wrapper class and there is no trace of this brand at runtime.

There's never any trace of typescript types at runtime.

By “trace” I think GP meant that the required wrapper is still there at runtime but was only in service of the type system.

Re: Branded types for TypeScript

#15

Earlier quoted context omitted.

You might need to read the article again, because those things are unrelated. Or you should explain what you mean.

I read the article, thanks. It makes the claims that (1) a string of a specific form (a hash) could be misused (eg. someone might call toUpper on it) or (2) passed in incorrect order to a function that takes multiple strings. Named parameters / outward-facing labels (Swift) completely solves (2). For (1), the solution is just ugly. Just use the type system in a normal manner and make a safe class “Hash” that doesn’t…

Respectfully disagree on the elegance. This looks pretty neat to me:

    type Hash = Branded;

Re: Branded types for TypeScript

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

> In most languages, doing what this article describes is quite straightforward Well, no. In most languages you wind up making a typed wrapper object/class that holds the primitive. This works fine, you can just do that in TypeScript too. The point of branded types is that you're not introducing a wrapper class and there is no trace of this brand at runtime.

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 like nominal typing for the branded type only.

It is more like "doing what this article describes" is the default behaviour of most languages (most languages use nominal typing).

Re: Branded types for TypeScript

#18

Earlier quoted context omitted.

> In most languages, doing what this article describes is quite straightforward Well, no. In most languages you wind up making a typed wrapper object/class that holds the primitive. This works fine, you can just do that in TypeScript too. The point of branded types is that you're not introducing a wrapper class and there is no trace of this brand at runtime.

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…

Indeed, this is what I was trying to say!

Re: Branded types for TypeScript

#19

Earlier quoted context omitted.

> In most languages, doing what this article describes is quite straightforward Well, no. In most languages you wind up making a typed wrapper object/class that holds the primitive. This works fine, you can just do that in TypeScript too. The point of branded types is that you're not introducing a wrapper class and there is no trace of this brand at runtime.

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…

[deleted]

Re: Branded types for TypeScript

#20

Giving types names is sometimes useful, yes. To the extent that languages often have that as the only thing and maybe have somewhat second class anonymous types without names. It's called "nominal typing", because the types have names. I don't know why it's called "branded" instead here. There's probably a reason for the [syntax choice]. Old idea but a good one.

It's called branded because the article is talking about branded types a way to enable nominal typing inside the structural typing system of Typescript.

Saying "nominal type" wouldn't mean anything.

Post reply on HN