Live data from Hacker News

TypeScript: Branded Types

prosopo.io

201–209 of 209 posts

Re: TypeScript: Branded Types

#201
post #200

Earlier quoted context omitted.

I can't really argue with that. It's a way to get nominal types in a language that has structural typing. Even though the usage is simple, the implementation is more complicated than it should be. If for example the language was missing builtin hashmap type, its implementation would be nasty as well. I'm not a huge fan of typing systems, the thing I like the most in TypeScript is that you can use types as little as y…

> languages like go that intentionally lack features people will go as far down the rabbit hole as you let them, which is what the Go developers understand and are trying to account for: https://www.hyrumslaw.com

I understand it's merit. I just don' like it. I think it's at least 100 years too soon for that. Exploration is important.

Re: TypeScript: Branded Types

#202
post #146

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 regularly crashed with bizarre segfaults errors, the last time I used it.

Sounds like vscode integration few years ago, yes.

Re: TypeScript: Branded Types

#203
post #192

Earlier quoted context omitted.

it doesn't. never prevents reading and readonly prevents (over)writing. GP just focused on the never -part of your question.

never means nothing can be assigned to it, so in that sense it's already readonly

Correct, so the question should have been: is readonly necessary?

I wouldn’t call myself an expert in TypeScript’s type system (although I use it daily), so I’m not sure about that one.

I do know I would have omitted readonly if I did this myself, but perhaps by mistake.

Re: TypeScript: Branded Types

#204
post #175

Earlier quoted context omitted.

It’s very readable to me, and is much cleaner than the notation in the article. Is your problem the line wraps in the parent’s comment?

this is readable? export type Brand = T & { readonly [B in Brand as `__${B}_brand`]: never; }; I count 14 different pieces of punctuation. you might as well use Perl at that point.

Equivalent code in Python:

  from typing import NewType

Re: TypeScript: Branded Types

#205
post #176
post #166

Earlier quoted context omitted.

function foo(customerId, itemId, orderId) { if(!customer[customerId]) throw new Error("Customer with id=" + customerId + " does not exist"); if(!item[itemId]) throw new Error("Item with id=" + itemId + " does not exist"); if(!order[orderId]) throw new Error("Order with id=" + orderId+ " does not exist"); } Just an example of how you can detect errors early with defensive programming.

As oppose to a zero cost build time check, that's 3 expensive runtime DB checks, plus an account and a member could have the same ID, so it might run anyways but on the wrong DB rows.

You made two points that are correct in theory, but in practice those lookups would/could take micro-seconds, and the bug would be detected within minutes in a production environment. And it would take five minutes or less to patch.

Re: TypeScript: Branded Types

#206
post #177
post #166

Earlier quoted context omitted.

function foo(customerId, itemId, orderId) { if(!customer[customerId]) throw new Error("Customer with id=" + customerId + " does not exist"); if(!item[itemId]) throw new Error("Item with id=" + itemId + " does not exist"); if(!order[orderId]) throw new Error("Order with id=" + orderId+ " does not exist"); } Just an example of how you can detect errors early with defensive programming.

Yeah this is exactly why using primitive types for ids is bad. If you encode it in the type system then you cannot make this error and don't need to check it at runtime.

Most bugs are found at runtime. The static analysis mostly finds silly errors that are easy to fix. A great type system do make it easier to write spaghetti code though, and you can have one letter variable names - naming is difficult.

Re: TypeScript: Branded Types

#207
post #205
post #176

Earlier quoted context omitted.

As oppose to a zero cost build time check, that's 3 expensive runtime DB checks, plus an account and a member could have the same ID, so it might run anyways but on the wrong DB rows.

You made two points that are correct in theory, but in practice those lookups would/could take micro-seconds, and the bug would be detected within minutes in a production environment. And it would take five minutes or less to patch.

If you're cowboy coding as a solo dev, sure.

Re: TypeScript: Branded Types

#208
post #207
post #205

Earlier quoted context omitted.

You made two points that are correct in theory, but in practice those lookups would/could take micro-seconds, and the bug would be detected within minutes in a production environment. And it would take five minutes or less to patch.

If you're cowboy coding as a solo dev, sure.

We could argue if having 1-3 code cowboys is better then a large team. If the code cowboys can produce higher quality, quicker. They will be difficult to replace after many years though.

Re: TypeScript: Branded Types

#209

Earlier quoted context omitted.

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

Happens a lot with junction tables ime. e.g. At my last job we had three tables: user, stream, user_stream. user_stream is an N:N junction between a user and a stream A user is free to leave and rejoin a stream, and we want to retain old data. So each user_stream has columns id, user_id, stream_id (+ others) Issues occur when people write code like the following: streamsService.search({ withIds: userStreams.map((stre…

Would it help if the junction tables named something else? "Session" or "participations"?
Post reply on HN