Replies: 8 comments
-
I think it's named Type in this package PD: Thanks for the blog post 😄 |
Beta Was this translation helpful? Give feedback.
-
Thanks @tonivj5, it's definitely that 🌮 Hey @jhnns, I have a slightly different implementation. It's closer to the one from that nice blog article you linked. And the reason why I chose to pass an import {A} from 'ts-toolbelt'
type EUR = A.Type<number, 'eur'>
type USD = A.Type<number, 'usd'>
let eurWallet = 10 as EUR
let usdWallet = 15 as USD
eurWallet = usdWallet // error (unique, would let this pass) I'm marking this as a question, for the wiki. |
Beta Was this translation helpful? Give feedback.
-
Thanks for clarifying @pirix-gh 👍. I'm a little bit surprised that one |
Beta Was this translation helpful? Give feedback.
-
Well, (from my experience) I think this happens because that symbol is not tied to any variable (but a type instead). The type describes that it can be a So if you wanted a really unique symbol, you'd have to do: declare const Foo: unique symbol;
type uniqueSymbol = typeof Foo; Which is not something that we can do dynamically. This is why I chose this implementation instead :) Cheers |
Beta Was this translation helpful? Give feedback.
-
Makes sense 👍. Picking an arbitrary id from a global namespace is not an ideal solution, but probably the best we can do :) |
Beta Was this translation helpful? Give feedback.
-
I just found out that your implementation of an opaque type allows the following: type Type<A extends any, Id extends string> = A & {
__type__?: Id;
};
type EUR = Type<number, 'eur'>
type USD = Type<number, 'usd'>
let eurWallet: EUR = 10 // is allowed, but should be an error
let usdWallet: USD = 15 // is allowed, but should be an error This is because Maybe we're talking about different use cases of opaque types, but this is a thing I want to prevent in my case. Imagine the following function: type Iban = Type<string, 'iban'>;
function doTransaction(iban: Iban) {
} I want to prevent people from calling function parseIban(str: string): Iban {
// do IBAN validation
// throw if invalid
return str as Iban;
}
doTransaction(parseIban("123")); What do you think? Should the current implementation be changed or should there be another opaque type? 😁 |
Beta Was this translation helpful? Give feedback.
-
Personally, I would even prefer to use a type OpaqueType<Type, TypeSymbol extends symbol> = Type & {__type__: TypeSymbol};
declare const IsoTimestampSymbol: unique symbol;
export type IsoTimestamp = OpaqueType<string, typeof IsoTimestampSymbol>; This way I can avoid the global string namespace. But you could make it optional of course: type OpaqueType<Type, TypeSymbol extends symbol | string> = Type & {__type__: TypeSymbol}; |
Beta Was this translation helpful? Give feedback.
-
Hey @jhnns, thanks for pointing this out. This is a regression, I just changed it recently late at night. It's a mistake. I integrated your suggestion this way: export type Type<A extends any, Id extends Key> =
A & {__type__: Id}
declare const crypto: unique symbol
type BTC = Type<number, typeof crypto>
type EUR = Type<number, 'eur'>
type USD = Type<number, 'usd'>
let btcWallet = 0.1 as BTC
let eurWallet = 10 as EUR
let usdWallet = 15 as USD
eurWallet = btcWallet // errors again, works The fix will be out within 5 minutes. Again, sorry about this and thanks for reaching out. |
Beta Was this translation helpful? Give feedback.
-
🍩 Feature Request
Is your feature request related to a problem?
While structural typing is great, it sometimes is desirable to have nominal typing: https://codemix.com/opaque-types-in-javascript/
Describe the solution you'd like
Taken from: https://github.com/sindresorhus/type-fest/blob/9ffc7c8a02358c7d0bac1ed62bdf183ed26a0546/source/opaque.d.ts
Describe alternatives you've considered
Teachability, Documentation, Adoption, Migration Strategy
I think the blog post describes the problem and the solution pretty well.
Beta Was this translation helpful? Give feedback.
All reactions