はじめに
こんにちは。
symbol-sdkの3.1.0が公開されました。(執筆時点の最新版)
直前の3.0.11のリリースノートを見てみると、
TypeScript support via JSDoc documentation
という文字が見えますね。
↓リリースノートのリンク
https://github.com/symbol/symbol/releases/tag/sdk%2Fjavascript%2Fv3.0.11
ということで、TypeScriptに対応したみたいなので、少し試してみたいと思います。
まずは転送トランザクションを作ってみる
以前書いた記事を例に、転送トランザクションを作ってみようと思います。
セットアップ
まずは必要なパッケージをインストールします。
$ npm init -y
$ npm install typescript symbol-sdk@3.1.0 axios
tsconfig.json
を作ります。
$ npx tsc --init
まずは動作確認がてら、簡単なコードを書いてみます。
import symbolSdk from 'symbol-sdk'
const network = symbolSdk.symbol.Network.TESTNET
console.log(network)
トランスパイルして実行します。
$ npx tsc
$ node test1.js
するとエラーになりました。
const symbol_sdk_1 = __importDefault(require("symbol-sdk"));
^
Error [ERR_REQUIRE_ESM]: require() of ES Module <略>node_modules\symbol-sdk\src\index.js from <略>test1.js not supported.
Instead change the require of index.js in <略> to a dynamic import() which is available in all CommonJS modules.
at Object.<anonymous> (<略>) {
code: 'ERR_REQUIRE_ESM'
}
CommonJSであるtest1.jsから、ESModuleのsymbol-sdkは参照できない、と言われました。
ですので、設定をESModuleにしていきます。package.json
に以下の項目を追加します。
{
"type": "module`
}
では、もう一度トランスパイルして実行してみます。
$ npx tsc
$ node test1.js
するとまたエラーになりました。
Object.defineProperty(exports, "__esModule", { value: true });
^
ReferenceError: exports is not defined in ES module scope
This file is being treated as an ES module because it has a '.js' file extension and '<略>\package.json' contains "type": "module". To treat it as a CommonJS script, rename it to use the '.cjs' file extension.
ESModuleでexportsは使えませんよ、と言われました。調べた感じでは、トランスパイルがCommonJSで出力しているのが問題なようです。
tsconfig.json
を以下のように修正します。
{
"compilerOptions": {
"module": "NodeNext"
}
}
それではもう一度。
$ npx tsc
$ node test1.js
Network {
name: 'testnet',
identifier: 152,
datetimeConverter: NetworkTimestampDatetimeConverter {
epoch: 2022-10-31T21:07:47.000Z,
timeUnits: 1
},
<以下略>
これは実行することができました。
次に以下のコードを試してみます。
const fee = 1000000n
これをトランスパイルしてみます。
$ npx tsc
エラーになりました。
<略> - error TS2737: BigInt literals are not available when targeting lower than ES2020.
1 const fee = 1000000n
~~~~~~~~
というわけでtsconfig.json
を以下のようにしました。
{
"compilerOptions": {
"target": "es2020"
}
}
これで動くようになりました。
転送トランザクション
まずはデッドラインと鍵ペアです。
const network = symbolSdk.symbol.Network.TESTNET
const deadline = network.fromDatetime(new Date(Date.now() + 60000)).timestamp
const facade = new symbolSdk.facade.SymbolFacade(network.name)
const privateKey = new symbolSdk.PrivateKey(PRIVATE_KEY)
// const keyPair = new facade.constructor.KeyPair(privateKey)
const keyPair = new symbolSdk.symbol.KeyPair(privateKey)
コメントアウトの行に示すように、new facade.constructor.KeyPair
は使えませんでした(エディターでエラー表示になりました)。代わりに、new symbolSdk.symbol.KeyPair
を使います(探しました)。
次にトランザクションです。
const currencyMosaicId = 0x72C0212E67A08BCEn
const transaction = facade.transactionFactory.create({
type: 'transfer_transaction_v1',
signerPublicKey: keyPair.publicKey.toString(),
fee: 1000000n,
deadline,
recipientAddress: 'TARDV42KTAIZEF64EQT4NXT7K55DHWBEFIXVJQY',
mosaics: [
{ mosaicId: currencyMosaicId, amount: 1000000n },
]
})
ここは特に問題なく、javascriptと同じように書けました。ただ、TypeScriptになったものの、transactionFactory.create
の引数はobject
型になっており、ここでは型定義の恩恵が受けられません。
そして署名です。
const signature = facade.signTransaction(keyPair, transaction)
// const jsonPayload = facade.transactionFactory.constructor.attachSignature(transaction, signature)
const jsonPayload = symbolSdk.symbol.SymbolTransactionFactory.attachSignature(transaction, signature)
const hash = facade.hashTransaction(transaction).toString()
console.log(jsonPayload);
console.log(hash);
コメントアウトの行が示すように、facade.transactionFactory.constructor.attachSignature
が使用できなかったので、symbolSdk.symbol.SymbolTransactionFactory.attachSignature
を使用しています。
最後に送信です。
// const sendRes = await axios.put(`${NODE_URL}/transactions`, jsonPayload).then((res) => res.data)
const sendRes = await axios.put(`${NODE_URL}/transactions`, JSON.parse(jsonPayload)).then((res) => res.data)
console.log(sendRes)
await new Promise((resolve) => setTimeout(resolve, 1000))
await axios
.get(`${NODE_URL}/transactionStatus/${hash}`).then((res) => res.data)
.then((statusRes) => {
console.log(statusRes)
})
.catch((e) => {
console.log(e.message, e.response.data)
});
コメントアウトの行が示すように、jsonPayload
に対して、JSON.parse
するようにしています。jsonPayload
はstring
型なのですが、axios
の仕様なのか、axios.put
の第二引数に文字列型を渡すと、リクエストのContent-Type
がapplication/x-www-form-urlencoded
で飛んで行ってしまいました。
ですので、オブジェクトを渡すようにして、application/json
でリクエストが飛ぶようにしています。
まとめ
やってきたことをまとめます。
package.json
に以下を追加する。
{
"type": "module`
}
tsconfig.json
を以下のように設定する。
{
"compilerOptions": {
"target": "es2020",
"module": "NodeNext"
}
}
JavaScriptのコードはそのままでは動かないため、適宜修正を行う。
となります。
symbol-sdk@3.1.0が、晴れてTypeScriptに対応しましたので、reactやvueでも使ってみようと思いました。