Live data from Hacker News

Adding type safety to object IDs in TypeScript

kravchyk.com

11–20 of 61 posts

Re: Adding type safety to object IDs in TypeScript

#12
post #5

This is pretty close to type branding (newtype wrapping for the Haskell-inclined), though using template literal types is pretty novel. Normal brands look something like this: type Brand = BaseType & { readonly __brand__: Brand }; type FooId = Brand ; function fooBar(asdf: FooId | 'foobar'): void { } fooBar will only accept the literal string 'foobar' or a true FooId, but not any arbitrary string. FooId would then co…

The easiest way I know of is

    declare const isMyID: unique symbol;
    export type MyID = string & { [isMyID]: true };

Re: Adding type safety to object IDs in TypeScript

#13
post #3

I wonder if a similar (but maybe more bloated) implementation using interfaces (and probably generics too?) will work in this case.

Something like this, maybe?

https://www.typescriptlang.org/play?#code/C4TwDgpgBAkgIlAvFA...

Alternatively, with generics: https://www.typescriptlang.org/play?#code/JYOwLgpgTgZghgYwgA...

I don't think these are better, to be honest. The string types suffice and are easier to exchange with servers and other APIs.

Re: Adding type safety to object IDs in TypeScript

#14
post #5

This is pretty close to type branding (newtype wrapping for the Haskell-inclined), though using template literal types is pretty novel. Normal brands look something like this: type Brand = BaseType & { readonly __brand__: Brand }; type FooId = Brand ; function fooBar(asdf: FooId | 'foobar'): void { } fooBar will only accept the literal string 'foobar' or a true FooId, but not any arbitrary string. FooId would then co…

It is also convenient to use a unique symbol for the brand (declare const brand: unique symbol). Then we can combine multiple brands in the same type and if we don't export that symbol type, we simply dont have a way to access the brand property at runtime.

Re: Adding type safety to object IDs in TypeScript

#15
post #7
post #5

This is pretty close to type branding (newtype wrapping for the Haskell-inclined), though using template literal types is pretty novel. Normal brands look something like this: type Brand = BaseType & { readonly __brand__: Brand }; type FooId = Brand ; function fooBar(asdf: FooId | 'foobar'): void { } fooBar will only accept the literal string 'foobar' or a true FooId, but not any arbitrary string. FooId would then co…

I prefer the Brand solution, it works well for existing ID sets that you can't easily migrate to have an actual string prefix

Also for values that aren't strings at all.

Re: Adding type safety to object IDs in TypeScript

#17
post #16

Its bit sad that startsWith doesn't narrow the type, making this pattern slightly less convenient. The GH issue: https://github.com/microsoft/TypeScript/issues/46958

What is the problem with the workaround suggested in the last comment there?

Re: Adding type safety to object IDs in TypeScript

#18
Not sure if it’s a valid point, but what I would like to have - kind of a regex or a template for strings or numbers. Otherwise, it’s still just a sting or a specific value. It’s not like you are free to update backend to prefix ids to your liking. Most of the time you have to work with set schemas.

Re: Adding type safety to object IDs in TypeScript

#20
post #18

Not sure if it’s a valid point, but what I would like to have - kind of a regex or a template for strings or numbers. Otherwise, it’s still just a sting or a specific value. It’s not like you are free to update backend to prefix ids to your liking. Most of the time you have to work with set schemas.

API models like Smithy can do that.
Post reply on HN