@scale-codec/enum
Version:
Simple JavaScript abstraction around Rust Enums
241 lines (155 loc) • 5.21 kB
Markdown
# @scale-codec/enum
## 2.1.1
### Patch Changes
- c3d70a8: **docs**: fix doc comment for `RustResult`
- c3d70a8: **docs**: update README
## 2.1.0
### Minor Changes
- 7da2814: **feature**: add typed `Variant.as()` method to cast a variant to a particular tag:
```ts
declare const value: Enumerate<{
Foo: [string]
Bar: [number]
Baz: []
}>
if (value.tag === 'Foo') {
const str: string = value.as('Foo')
// type error
const num: number = value.as('Bar') // => never
}
value.as('Baz') // => never
```
## 2.0.0
### Major Changes
- 7e81bbc: **refactor**: introduce a new design of tagged unions
#### What is the change
Enums are declared with `Enumerate<T>` type.
**Enum in Rust:**
```rust
enum Message {
Ping,
Text(String),
Coords(u32, u32),
User { name: String }
}
```
**Enum in TypeScript with `@scale-codec/enum`:**
```ts
import { Enumerate } from '@scale-codec/enum'
type Message = Enumerate<{
Ping: []
Text: [string]
Coords: [[number, number]]
User: [{ name: string }]
}>
```
Once enum type is declared, it could be used to create its **variants**.
**Creating variants in Rust:**
```rust
let mut msg = Message::Ping;
msg = Message::Text("foo".to_owned());
msg = Message::Coords(4, 2);
msg = Message::User { name: "bar".to_owned() };
```
**Creating variants in TypeScript with `@scale-codec/enum`:**
```ts
import { variant } from '@scale-codec/enum'
let msg: Message = variant('Ping')
msg = variant('Text', 'foo')
msg = variant('Coords', [4, 2])
msg = variant('User', { name: 'bar' })
```
Each **variant instance** has `tag` and `content` fields to work with:
```ts
declare const msg: MessageVariant
if (msg.tag === 'Text') {
console.log(msg.content.trim())
}
```
There are other changes as well, but that's all for the major ones.
#### Why the change was made
The goal is to be consistent with [TypeScript support of discriminated unions](https://www.typescriptlang.org/docs/handbook/typescript-in-5-minutes-func.html#discriminated-unions). As a consequence, TypeScript can now narrow types and check for exhaustiveness in code that works with enums. In other words, **new enums are type-stronger**.
#### How a consumer should update their code
- Re-write enum declarations:
```ts
// before
type MyEnum = Enum<'None' | ['Some', string]>
// after
type MyEnum = Enum<{ None: []; Some: [string] }>
```
- Create variants with `variant` helper:
```ts
// before
const value1: MyEnum = Enum.variant('Some', 'foo')
// after
const value2 = variant<MyEnum>('Some', 'foo')
const value3: MyEnum = variant('Some', 'foo')
```
- Replace `Option` and `Result` imports with `RustOption` and `RustResult`.
- Remove `.match()` usage. If you need real pattern-matching in TypeScript, consider using `ts-pattern` library:
```ts
import { match } from 'ts-pattern'
import { VariantOf, RustOption } from '@scale-codec/enum'
declare const value: VariantOf<RustOption<string>>
const show = match(value)
.with({ tag: 'None' }, () => 'Nothing')
.with({ tag: 'Some', content: 'foo' }, () => 'Foo!')
.with({ tag: 'Some' }, ({ content }) => `Some(${content})`)
.exhaustive()
```
## 1.1.1
### Patch Changes
- 822202d: **fix**: specify `exports.*.types` field in `package.json` so TypeScript works fine in `nodenext` module resolution mode
## 1.1.0
### Minor Changes
- e72d4de: Change build artifacts: `lib.cjs.js` → `lib.cjs`, `lib.esm.js` → `lib.mjs`
## 1.0.2
### Patch Changes
- 1f92e19: **types**: extend `Enum.variant()` typing
## 1.0.1
### Patch Changes
- eeeb481: **fix**: fix typing for `.as()` return value
## 1.0.0
### Major Changes
- **feat**: **BREAKING** `Enum` now uses new definitions approach.
For example, instead of:
```ts
type OptNum = Enum<{
None: null
Some: { value: number }
}>
```
it should be:
```ts
type OptNum = Enum<'None' | ['Some', number]>
```
This definition way is much easier for TypeScript to handle, and it allows to avoid some constraints and auto-inference problems
- **feat**: **BREAKING** `empty()` and `valuable()` static methods are replaced with a single `variant()` creation factory. It is type-safe and easy to use thanks to the new definitions approach.
For example, instead of:
```ts
type OptNum = Option<number>
const opt1: OptNum = Enum.empty('None')
const opt2: OptNum = Enum.valuable('Some', 42)
```
it should be:
```ts
const opt3: OptNum = Enum.variant('None')
const opt4: OptNum = Enum.variant('Some', 42)
```
## 0.2.2
### Patch Changes
- b4c91cf: **feat**: better error messages when use `.as(tag)`
## 0.2.1
### Patch Changes
- 27b7927: Add build status badge to the README
## 0.2.0
### Minor Changes
- c78d861: **Breaking changes**:
- drop `create()` static method, add `valuable()` and `empty()` instead
- update internal fields which are used by other packages
### Patch Changes
- 26c9dd0: Update readme and `homepage` at `package.json`
- 334a28d: Add keywords to package.json
## 0.1.1
### Patch Changes
- b79934e: Add more inline documentation