Live data from Hacker News

TypeScript: Branded Types

prosopo.io

131–140 of 209 posts

Re: TypeScript: Branded Types

#131
post #45

Earlier quoted context omitted.

`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 a…

Isn't that what you want to signify? It's the intent, and better than asserting that your IDs have a string-valued field that it doesn't. Ideally you could brand with a private field, but we would probably need `typeof class` for that (assuming `typeof class` allows private members. I'm not sure).

> Isn't that what you want to signify? It's the intent

No it isn't. If your ids do have a field, then marking them as never having a field is unwise. Never means that code that reads that field is never wrong (because you can never reach the point of reading it), whereas you want the opposite, code that reads that field is always wrong.

Re: TypeScript: Branded Types

#132
post #48

Earlier quoted context omitted.

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

You can google, gpt or look at wikipedia for "liskov substitution principles". It's related to object oriented programming, more specifically to inheritance and what is allowed as substitution as superclass vs subclass depending on which position it sits in argument vs return value. It's very interesting read if you don't know about it and you're using OOP. What advanced types do you have in mind? ps. the way you're…

I know what SOLID is, questioning how exactly you think Flow has "liskov substitution" as a feature.

Re: TypeScript: Branded Types

#134

An example of what you can implement on top of branded types that I want to share with fellow hackers: - currencies You may have some sort of integer representing the number of cents of some currency and you want to avoid doing operations between the wrong currencies (such as adding euros and pesos). You can create branded types and functions that work on those Euro branded numbers and then decide how to do math on i…

Thanks, the currency stuff was a great real-world example that crystallized where this would be nice to have at a core level with typescript to severely reduce the odds of doing cross-currency math.

Re: TypeScript: Branded Types

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

TypeScript _itself_ has a branded primitive string type it uses internally.[1] Dedicated syntax for creating unique subsets of a type that denote a particular refinement is a longstanding ask[2] - and very useful, we've experimented with implementations.[3]

I don't think it has any relation to runtime type checking at all. It's refinement types, [4] or newtypes[5] depending on the details and how you shape it.

[1] https://github.com/microsoft/TypeScript/blob/main/src/compil... [2] https://github.com/microsoft/TypeScript/issues/4895 [3] https://github.com/microsoft/TypeScript/pull/33038 [4] https://en.wikipedia.org/wiki/Refinement_type [5] https://wiki.haskell.org/Newtype

Re: TypeScript: Branded Types

#136
post #26

Earlier quoted context omitted.

Ah, yeah the error makes sense. I expected the error, just wanted to understand how Brand was meant to be actually assigned to a primitive. I'm not sure the function is necessary though. This does the same thing const accountId = "125314" as AccountId It makes sense that the technique uses casting.

That's a very clear example. But what if I instead wrote: const accountId = AccountId ("125314" ); There would be the needed checks and balances in the function AccountId(). Wouldn't that do pretty much the same thing?

I personally prefer less code and more explicit casting

Re: TypeScript: Branded Types

#137
post #26

Earlier quoted context omitted.

Ah, yeah the error makes sense. I expected the error, just wanted to understand how Brand was meant to be actually assigned to a primitive. I'm not sure the function is necessary though. This does the same thing const accountId = "125314" as AccountId It makes sense that the technique uses casting.

The function is great in cases where you can validate the string, or paired with lint rules that limit casting.

At that point I'd just use a class constructor.

Re: TypeScript: Branded Types

#138

An example of what you can implement on top of branded types that I want to share with fellow hackers: - currencies You may have some sort of integer representing the number of cents of some currency and you want to avoid doing operations between the wrong currencies (such as adding euros and pesos). You can create branded types and functions that work on those Euro branded numbers and then decide how to do math on i…

As much as I love branding, I would be hesitant to use it for critical math and where you might want to inspect the type at runtime as with money.

Branding is easily circumvented, so it's best as a developer hint that helps document APIs and alerts us to common mistakes as an incremental improvement over primitives.

For money and similar I would use objects and a custom math library.

Re: TypeScript: Branded Types

#139
post #137

Earlier quoted context omitted.

The function is great in cases where you can validate the string, or paired with lint rules that limit casting.

At that point I'd just use a class constructor.

That has a lot of overhead compared to validating and casting a primitive.

Re: TypeScript: Branded Types

#140
post #109

Isn't this just the classic issue of inferred typing coming back to bite us in the way everyone originally predicted? Go runs into the same issue where wildly different types may be considered the same based purely on coincidental naming and matching against interfaces the original authors had no intent to match against. At the end of the day I think the easier system to work with is one in which all type compatibili…

The other problem I've found with structural types in Typescript is that it can lead to some very complex type specifications. Instead of carefully thinking about and naming the entities in your system you can get some very hard to parse type spaghetti.
Post reply on HN