Things I wish I knew... (#1374)
* Make a start * Intro * Installation * Flatten * Move METHODS_*.md to substrate/*.md * Basics * Apply suggestions from code review Co-Authored-By: Thibaut Sardan <33178835+Tbaut@users.noreply.github.com> * Substrate links * Create * api.consts * Typo * Typo, ms -> md * types.basics (SIP) * Type basics * api.consts jumps to api.query * Start to api.query * Basic queries * Point starting to actual overview * api.rpc * Derive detour * Query subs & query multi * Apply suggestions from code review Co-Authored-By: Thibaut Sardan <33178835+Tbaut@users.noreply.github.com> * typo * Query extras * Basic transactions * Misplaced , * keyring WIP * Keyring wrap-up * Subs SIP * tx subs more WIP * tx subs * Small types cleanups * Apply suggested changes from @JoshOrndorff * Clarify naked await * tx wrapping WIP * Wrap api.wrap * TS placeholder * [WIP] markers for not-started * Clarifying comments * Additional clarifications * types.extend... well, extended... * Remove *nix * Warp up TypeScript... it is it (for now) * Some small text clarifications * Some cleanups * Cleanups, typos * keyring cleanups * Cleanups * Wrap * api.wrap wrapped... hopefully * typos * Registration typos * typescript typos, hope I caught most...
This commit is contained in:
co-authored by
Thibaut Sardan
parent
3e417f4f94
commit
55fb391465
@@ -0,0 +1,67 @@
|
||||
# Introduction to types
|
||||
|
||||
We've touched upon types in most previous sections, i.e. that these are driven by metadata and that they are created and converted to/from automatically by the API. Since they appear in all results, we will divert a bit from the regularly scheduled program in explaining the API interfaces to giving some info on the base types.
|
||||
|
||||
## Everything is a type
|
||||
|
||||
Just to re-iterate from the above. Eveything returned by the API is a type and has a consistent interface. This means that a `Vec<u32>` (an array of `u32` values) as well as a `Struct` (an pre-defined object) or an `Enum` has the same consistent base interface. Specific types types will have values, based on the type - decorated and available.
|
||||
|
||||
As a minimum, anything returned by the API, be it a `Vec<...>`, `Option<...>`, `Struct` or any normal type will always have the following methods -
|
||||
|
||||
- `.eq(<other value>)` - checks for equality against the other value. In all cases, it will accept "like" values, i.e. in the case of a number you can pass a primitive (such as `1`), a hex value (such as `0x01`) or even an `Unit8Array`
|
||||
- `toHex()` - returns a hex-base representation of the value, always prefixed by `0x`
|
||||
- `toJSON()` - returns a JSON-like representation of the value, this is generally used when calling `JSON.stringify(...)` on the value
|
||||
- `toString()` - returns a string representation, in some cases this performs additional encoding, i.e. for `Address`, `AccountId` and `AccountIndex` it will encode to the ss58 address
|
||||
- `.toU8a()` - returns a `Uint8Array` representation of the encoded value (generally exactly as passed to the node, where values are SCALE encoded)
|
||||
|
||||
Additionally, the following getters and utilities are available -
|
||||
|
||||
- `.isEmpty` - `true` if the value is an all-empy value, i.e. `0` in for numbers, all-zero for Arrays (or anything `Uint8Array`), `false` is non-zero
|
||||
- `.hash` - a `Hash` (once again with all the methods above) that is a `blake2-256` representation of the contained value
|
||||
|
||||
## Working with numbers
|
||||
|
||||
All numbers wrap and extend an instance of [bn.js](https://github.com/indutny/bn.js/). This means that in addition to the interfaces defined above, they have some additional methods -
|
||||
|
||||
- `.toNumber()` - a JS number (limited to 2^53 - 1). This does mean that for large values, e.g. `Balance` (a `u128` extension), this can cause overflows
|
||||
- `.add(...)`, `.sub(...)`, ... - all the base methods available on the `BN` object
|
||||
|
||||
In cases where a `Compact` is returned, i.e. `Compact<Balance>`, the value is wrapped. This object should be `.unwrap()`-ed first to gain access to the underlying `Balance` object.
|
||||
|
||||
## Working with structures
|
||||
|
||||
All structures, a wrapping of an object containing a number of member variables, is an implementation of a standard JS `Map` object, so all the functions available on a `Map` such as `.entries()` are available. Additionally it is decorated with actual getters for the fields.
|
||||
|
||||
As an example, a `Header` will have getters for the `.parentHash`, `.number`, `.stateRoot`, `.extrinsicsRoot` and `.digest` fields. The same applies for all structures, as they are returned, each member will have an associated getter.
|
||||
|
||||
Be aware that in the JS version naming defaults to `camelCase` where names of fields in Substrate defaults to `snake_case`. (Each version aligning with conventions in the respective languages)
|
||||
|
||||
## Working with enums
|
||||
|
||||
Each enum has additional getters which are injected based on the fields wrapped. These take the form of `.is<Name>` and `.as<Name>` to allow you to check is the enum is a certain value or to retrieve the underlying value as a specific type.
|
||||
|
||||
As a real-world example, when an extrinsic is applied, the `Phase` enum has one of two states, `ApplyExtrinsic(u32)` or `Finalization`. In this case `.isApplyExtrinsic` would be `true` when an extrinsic is being applied, and `.asApplyExtrinsic` would return the value as a `u32` (which is the index of the extrinsic in the block, as it is being applied). When `isisApplyExtrinsic` is `false` and `asApplyExtrinsic` is called, the getter will throw.
|
||||
|
||||
## Working with Option<Type>
|
||||
|
||||
An `Option<Type>` attempts to mimic the Rust approach of having `None` and `Some` available. This means the following getters & methods are available on an `Option` -
|
||||
|
||||
- `.isNone` - is `true` if no underlying values is warpped, effectively the same as `.isEmpty`
|
||||
- `.isSome` - this is `true` is a value is wrapped, i.e. if a `Option<u32>` has an actual underlying `u32`
|
||||
- `.unwrap()` - when `isSome`, this will return the wrapped value, i.e. for `Option<u32>`, this would return the `u32`. When the value is `isNone`, this call will throw an exception.
|
||||
- `.unwrapOr(<default value>)` - this extends `unwrap()`, returning the wrapped value when `isSome` and in the case of `isNone` it will return the `<default value>` passed.
|
||||
|
||||
## Working with Tuples
|
||||
|
||||
A tuple is defined in the form of `(u32, AccountId)`. To access the individual values, you can access t via the index, i.e.
|
||||
|
||||
```js
|
||||
// assuming a tuple defined as `(32, AccountId)`
|
||||
const [count, accountId] = tuple;
|
||||
|
||||
console.log(`${accountId} has ${count.toNumber()} values`);
|
||||
```
|
||||
|
||||
## Extending types
|
||||
|
||||
For customized chains, the need exists to register types so the API is aware of how to decode values for those types. The next section will provide a [walk-through for the definition of custom types](types.extend.md) allowing the definition or re-definition of any type the API is aware of.
|
||||
Reference in New Issue
Block a user