TypeScript
Requirements
Khizab is designed to be as type-safe as possible! Things to keep in mind:
- Types currently require using TypeScript >=5.0.4.
- TypeScript doesn't follow semver and often introduces breaking changes in minor releases.
- Changes to types in this repository are considered non-breaking and are usually released as patch changes (otherwise every type enhancement would be a major version!).
- It is highly recommended that you lock your
khizab
andtypescript
versions to specific patch releases and upgrade with the expectation that types may be fixed or upgraded between any release. - The non-type-related public API of Khizab still follows semver very strictly.
To ensure everything works correctly, make sure your tsconfig.json
has strict
mode set to true
.
{
"compilerOptions": {
"strict": true
}
}
{
"compilerOptions": {
"strict": true
}
}
Config Types
By default React Context does not work well with type inference. To support strong type-safety across the React Context boundary, there are two options available:
- Declaration merging to "register" your
config
globally with TypeScript. config
property to pass yourconfig
directly to hooks.
Declaration Merging
Declaration merging allows you to "register" your config
globally with TypeScript. The Register
type enables Khizab to infer types in places that wouldn't normally have access to type info via React Context alone.
To set this up, add the following declaration to your project. Below, we co-locate the declaration merging and the config
set up.
import { createConfig } from 'khizab'
import { mainnet } from 'khizab/networks'
declare module 'khizab' {
interface Register {
config: typeof config
}
}
export const config = createConfig({
network: mainnet
})
import { createConfig } from 'khizab'
import { mainnet } from 'khizab/networks'
declare module 'khizab' {
interface Register {
config: typeof config
}
}
export const config = createConfig({
network: mainnet
})
Since the Register
type is global, you only need to add it once in your project. Once set up, you will get strong type-safety across your entire project.
ts
import {useBlockByHeight } from 'khizab'useBlockByHeight ({height : 359251780,withTransactions : true})
ts
import {useBlockByHeight } from 'khizab'useBlockByHeight ({height : 359251780,withTransactions : true})
You just saved yourself a runtime error and you didn't even need to pass your config
. 🎉
Hook config
Property
For cases where you have more than one Khizab config
or don't want to use the declaration merging approach, you can pass a specific config
directly to hooks via the config
property.
import { createConfig } from 'khizab'
import { mainnet, testnet } from 'khizab/networks'
export const configA = createConfig({
network: mainnet,
})
export const configB = createConfig({
network: testnet,
})
import { createConfig } from 'khizab'
import { mainnet, testnet } from 'khizab/networks'
export const configA = createConfig({
network: mainnet,
})
export const configB = createConfig({
network: testnet,
})
As you expect, network
is inferred correctly for each config
.
ts
import {useBlockByHeight } from 'khizab'useBlockByHeight ({height : 359251780,withTransactions : true,config :configA })useBlockByHeight ({height : 359251780,withTransactions : true,config :configB })
ts
import {useBlockByHeight } from 'khizab'useBlockByHeight ({height : 359251780,withTransactions : true,config :configA })useBlockByHeight ({height : 359251780,withTransactions : true,config :configB })
This approach is more explicit, but works well for advanced use-cases, if you don't want to use React Context or declaration merging, etc.
Const-Assert ABIs & Typed Data
Khizab can infer types based on ABIs. This achieves full end-to-end type-safety from your contracts to your frontend and enlightened developer experience by autocompleting ABI item names, catching misspellings, inferring argument and return types, and more.
For this to work, you must either const-assert ABIs . For example, useReadContract
's abi
configuration parameter:
const abi = […] as const // <--- const assertion
const { data } = useReadContract({ abi })
const abi = […] as const // <--- const assertion
const { data } = useReadContract({ abi })
If type inference isn't working, it's likely you forgot to add a const
assertion or define the configuration parameter inline. Also, make sure your ABIs, and TypeScript configuration are valid and set up correctly.
TIP
Unfortunately TypeScript doesn't support importing JSON as const
yet. Check out the Khizab CLI to help with this! It can automatically fetch ABIs from Aptos Blockchain, generate React Hooks, and more.
Anywhere you see the abi
configuration property, you can likely use const-asserted to get type-safety and inference. These properties are also called out in the docs.
Here's what useReadContract
looks like with const-asserted abi
property.
ts
import {useReadContract } from 'khizab'const {data } =useReadContract ({abi ,functionName : 'get_todo_list_counter',args : ['0x00000'],})data
ts
import {useReadContract } from 'khizab'const {data } =useReadContract ({abi ,functionName : 'get_todo_list_counter',args : ['0x00000'],})data