You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: readme.md
+4-4
Original file line number
Diff line number
Diff line change
@@ -151,8 +151,8 @@ Click the type names for complete docs.
151
151
-[`UndefinedOnPartialDeep`](source/undefined-on-partial-deep.d.ts) - Create a deep version of another type where all optional keys are set to also accept `undefined`.
152
152
-[`ReadonlyDeep`](source/readonly-deep.d.ts) - Create a deeply immutable version of an `object`/`Map`/`Set`/`Array` type. Use [`Readonly<T>`](https://www.typescriptlang.org/docs/handbook/utility-types.html#readonlytype) if you only need one level deep.
153
153
-[`LiteralUnion`](source/literal-union.d.ts) - Create a union type by combining primitive types and literal types without sacrificing auto-completion in IDEs for the literal type part of the union. Workaround for [Microsoft/TypeScript#29729](https://github.com/Microsoft/TypeScript/issues/29729).
154
-
-[`Tagged`](source/opaque.d.ts) - Create a [tagged type](https://medium.com/@KevinBGreene/surviving-the-typescript-ecosystem-branding-and-type-tagging-6cf6e516523d) that can support [multiple tags](https://github.com/sindresorhus/type-fest/issues/665) and [per-tag metadata](https://medium.com/@ethanresnick/advanced-typescript-tagged-types-improved-with-type-level-metadata-5072fc125fcf). (This replaces the previous [`Opaque`](source/opaque.d.ts) type, which is now deprecated.)
155
-
-[`UnwrapTagged`](source/opaque.d.ts) - Get the untagged portion of a tagged type created with `Tagged`. (This replaces the previous [`UnwrapOpaque`](source/opaque.d.ts) type, which is now deprecated.)
154
+
-[`Tagged`](source/tagged.d.ts) - Create a [tagged type](https://medium.com/@KevinBGreene/surviving-the-typescript-ecosystem-branding-and-type-tagging-6cf6e516523d) that can support [multiple tags](https://github.com/sindresorhus/type-fest/issues/665) and [per-tag metadata](https://medium.com/@ethanresnick/advanced-typescript-tagged-types-improved-with-type-level-metadata-5072fc125fcf).
155
+
-[`UnwrapTagged`](source/tagged.d.ts) - Get the untagged portion of a tagged type created with `Tagged`.
156
156
-[`InvariantOf`](source/invariant-of.d.ts) - Create an [invariant type](https://basarat.gitbook.io/typescript/type-system/type-compatibility#footnote-invariance), which is a type that does not accept supertypes and subtypes.
157
157
-[`SetOptional`](source/set-optional.d.ts) - Create a type that makes the given keys optional.
158
158
-[`SetReadonly`](source/set-readonly.d.ts) - Create a type that makes the given keys readonly.
Attach a "tag" to an arbitrary type. This allows you to create distinct types, that aren't assignable to one another, for runtime values that would otherwise have the same type. (See examples.)
11
-
12
-
The generic type parameters can be anything.
13
-
14
-
Note that `Opaque` is somewhat of a misnomer here, in that, unlike [some alternative implementations](https://github.com/microsoft/TypeScript/issues/4895#issuecomment-425132582), the original, untagged type is not actually hidden. (E.g., functions that accept the untagged type can still be called with the "opaque" version -- but not vice-versa.)
15
-
16
-
Also note that this implementation is limited to a single tag. If you want to allow multiple tags, use `Tagged` instead.
17
-
18
-
[Read more about tagged types.](https://medium.com/@KevinBGreene/surviving-the-typescript-ecosystem-branding-and-type-tagging-6cf6e516523d)
19
-
20
-
There have been several discussions about adding similar features to TypeScript. Unfortunately, nothing has (yet) moved forward:
type AccountNumber = Opaque<number, 'AccountNumber'>;
30
-
type AccountBalance = Opaque<number, 'AccountBalance'>;
31
-
32
-
// The `Token` parameter allows the compiler to differentiate between types, whereas "unknown" will not. For example, consider the following structures:
33
-
type ThingOne = Opaque<string>;
34
-
type ThingTwo = Opaque<string>;
35
-
36
-
// To the compiler, these types are allowed to be cast to each other as they have the same underlying type. They are both `string & { __opaque__: unknown }`.
37
-
// To avoid this behaviour, you would instead pass the "Token" parameter, like so.
38
-
type NewThingOne = Opaque<string, 'ThingOne'>;
39
-
type NewThingTwo = Opaque<string, 'ThingTwo'>;
40
-
41
-
// Now they're completely separate types, so the following will fail to compile.
42
-
function createNewThingOne (): NewThingOne {
43
-
// As you can see, casting from a string is still allowed. However, you may not cast NewThingOne to NewThingTwo, and vice versa.
44
-
return 'new thing one' as NewThingOne;
45
-
}
46
-
47
-
// This will fail to compile, as they are fundamentally different types.
48
-
const thingTwo = createNewThingOne() as NewThingTwo;
49
-
50
-
// Here's another example of opaque typing.
51
-
function createAccountNumber(): AccountNumber {
52
-
return 2 as AccountNumber;
53
-
}
54
-
55
-
function getMoneyForAccount(accountNumber: AccountNumber): AccountBalance {
56
-
return 4 as AccountBalance;
57
-
}
58
-
59
-
// This will compile successfully.
60
-
getMoneyForAccount(createAccountNumber());
61
-
62
-
// But this won't, because it has to be explicitly passed as an `AccountNumber` type.
63
-
getMoneyForAccount(2);
64
-
65
-
// You can use opaque values like they aren't opaque too.
66
-
const accountNumber = createAccountNumber();
67
-
68
-
// This will compile successfully.
69
-
const newAccountNumber = accountNumber + 2;
70
-
71
-
// As a side note, you can (and should) use recursive types for your opaque types to make them stronger and hopefully easier to type.
Attach a "tag" to an arbitrary type. This allows you to create distinct types, that aren't assignable to one another, for distinct concepts in your program that should not be interchangeable, even if their runtime values have the same type. (See examples.)
0 commit comments