4 ms·
Sorry, how do you apply it to branding primitives? The basic const accountId: Brand<string, "Account"> = "123654" Has the error Type 'string' is not
by cush 2y ago
Sorry, how do you apply it to branding primitives? The basic
const accountId: Brand<string, "Account"> = "123654"
Has the error
Type 'string' is not assignable to type '{ readonly __Account_brand: never; }'
- beeboobaa3 2y agoThis error is, in fact, the point. It keeps you from accidentally assigning a normal string to a branded string You have to make a function to apply the brand via a cast, the article explains this as well. function makeObjectId(id: string): ObjectId { return id as ObjectId; }
- cush 2y agoAh, 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.
- spankalee 2y agoThe function is great in cases where you can validate the string, or paired with lint rules that limit casting.
- galaxyLogic 2y agoThat'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?
- svieira 2y agoYes, but then there would be runtime overhead for the wrapper (presuming a class or object is returned) or the type of accountId would be the underlying type (if AccountId isn't returning a branded type).
- cush 2y agoI personally prefer less code and more explicit casting
- whilenot-dev 2y agoconst accountId = "125314" as AccountId; or const accountId = new AccountId("125314"); or const accountId = accountIdFromString("125314"); is all "explicit" casting in my understanding, one way or the other, and the first ... as ... being on the lowest level. I'd rather go for something like "do the casting close to the source, and in general use 'parse, don’t validate'[0] when getting input from the outer world". [0]: https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-validate/ https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-va...
- cush 2y agoAgree. I was talking about const accountId = AccountId (“43525”) being less explicit
- usrusr 2y agoThe as also does not burden the reader with guessing about the absence of unexpected stuff happening in the functions. Don't pepper the code with mostly unused hidey-holes just to perhaps save some busywork later. If you do add valuation, make it an honest asValidatedAccountId("123"), not an accountIdFromString("123") that may or may not do more than casting. (PS, very much off topic: speaking of hidey-holes, are any of the AOP monstrosities still operational?)
- yencabulator 2y agoAnd herein lies one of the worst features of Typescript. const myCompanyId = something_complicated as CompanyId; where something_complicated actually is a UserId, not a bare string. It is way too easy to accidentally destroy type safety with `as`, there are absolutely 0 safeguards. I fear every single instance of `as` in any Typescript source I see.
- epolanski 2y agoWhich, in real life, makes you parse (and handle or throw errors or log, whatever you want) but then now that the item you have is what you need. Another way you can implement the same: through a class constructor like new UserId('some string') which can also throw or let you handle operations on the class itself while allowing you to get the value.