📝 Nim for TypeScript Programmers 日本語訳
目次
比較 | 変数 | 三項演算子 | 無名関数 |
This | アロー関数 | コンパイル時の関数実行 | サーバーサイドレンダリング |
クライアントサイドレンダリング | Svelte | Parcel | CommonJS |
WebGL GUI | Electron | Webview | React |
その他の GUI フレームワーク | WebAssembly | ビルドモード | 最小化 |
難読化 | JavaScript の相互接続性 | 相互接続のためのプラグマ | 相互接続性テンプレート |
正規表現 | Nim 用の HTML/CSS WYSYWIG エディタ | NodeJS での実行 | BigInt |
Fetch | ベストプラクティス | その他 |
免責事項!
非公式で、作業中です! これは代用品でしかないです。拡張にご協力ください。このガイドには不正確な点があるかもしれません。このガイドは、ある程度の中級の知識を想定しています。
公式チュートリアルはこちらでご覧になれます:
- Nim チュートリアル (パート 1)
- Nim チュートリアル (パート 2)
- Nim チュートリアル(パート 3)
公式マニュアルでは、言語の概要が説明されています:
- Nim マニュアル
公式ライブラリドキュメントには、Nim の標準ライブラリのドキュメントがあります:
- Nim 標準ライブラリ
比較
特徴 | TypeScript | Nim |
---|---|---|
これを使用して書かれた | TypeScript | Nim |
ライセンス | Apache | MIT |
バージョン | 3.x | 1.x |
型 | 静的、"確かに正しい" 型 | 静的、強力、推論 |
メタプログラミング | デコレータに制限がある | テンプレート、マクロ |
int8/16/32/64 型 | ❌ | ✅ |
float32/float64 型 | ❌ | ✅ |
Char 型 | ❌ | ✅ |
Subrange 型 | ❌ | ✅ |
JSON 型 | ❌ | ✅ |
Regex 型 | ❌ | ✅ |
オプション 型 | ❌ | ✅ |
オペレーターオーバーローディング | ❌ | ✅ |
カスタムオペレーター | ❌ | ✅ |
ランタイムチェック | ❌ | ✅ |
サイド・エフェクトトラッキング | ❌ | ✅ |
Enum 型 | ✅ | ✅ |
不変性 | 制限的、読み取り専用 キーワード |
✅ |
関数の引数は不変 | 可変 | 不変 |
完全な DOM API | ✅ | ✅ |
どこでも console.log()
|
❓ コンパイラが文句言う | ✅ |
どこでも console.assert()
|
❓ コンパイラが文句言う | ✅ |
NodeJS 統合 | ✅ | ✅ |
ジェネリクス | ✅ | ✅ |
型インターフェース | ✅ | ✅ |
クロージャ | ✅ | ✅ |
オブジェクト指向 | ✅ | ✅ |
メソッド | ✅ | ✅ |
例外処理 | ✅ | ✅ |
無名関数 | ✅ | ✅ |
アロー関数 | ✅ | ✅ |
配列内包表記 | ✅ | ✅ |
フォーマットされた文字列リテラル | ✅ | ✅ |
FFI | ✅ JS のみ | ✅ C/C++/JS |
Async | ✅ | ✅ |
正規表現 | ✅ | ✅ |
自己文書化コマンド | ✅ | ✅ |
パッケージ公開 | ✅ | ✅ |
パッケージマネージャー | ✅ | ✅ |
コード自動フォーマッター | ✅ NPM 経由 | ✅ Nimpretty |
ファイル拡張 | ✅ .ts、.tsx | ✅ .nim、.nims |
変数
新しい変数の作成は、var
、let
、const
を使います。Nim は不変量とコンパイル時の関数実行を備えています。const
は TypeScript とはちがって、真の意味で不変です。
特徴 | const |
let |
var |
---|---|---|---|
ランタイム | いいえ | ✅ はい | ✅ はい |
コンパイル時間 | ✅ はい | いいえ | いいえ |
不変 | ✅ はい | ✅ はい | いいえ |
自動初期化 | ✅ はい | ✅ はい | ✅ はい |
再割り当て可能 | いいえ | いいえ | ✅ はい |
割り当てが必要 | ✅ はい | ✅ はい | いいえ |
グローバルにすることができる | ✅ はい | ✅ はい | ✅ はい |
ゼロから始める場合、学習中に var
を使用してもエラーは発生しませんので、学習を進めることができます。
三項演算子
conditional ? "result0" : "result1"
⬆️ TypeScript ⬆️ ⬇️ Nim ⬇️
if conditional: "result0" else: "result1"
三項演算子が単なる if.else
のインラインであることにお気づきでしょうか。
無名関数
var myfunc = (argument1: number, argument2: number) => {
return argument1 + argument2
};
console.log( myfunc(1, 2) )
⬆️ TypeScript ⬆️ ⬇️ Nim ⬇️
var myfunc = ( proc (argument1, argument2: int): int = argument1 + argument2 )
echo myfunc(1, 2)
Nim では、無名関数とは、名前を持たず、大括弧で囲まれた関数のことです。
This
Nim の this
には固定の命名規則がないので、self
を使っているコードも見かけます。Nim は最初の引数であることにしかこだわらないので、this
や self
はデフォルトで 不変です。
type Cat = object
proc purr(this: Cat) = echo "Purr Purr" # 'this' を使っている
proc dance(self: Cat) = echo "Tappity Tappity" # 'self' を使っている
let garfield = Cat()
garfield.purr() # ゴロゴロ
garfield.dance() # タタタン
# うん、this/self はインスタンスだよ
proc himself(self: Cat): Cat = return self
echo garfield == garfield.himself() # true
アロー関数
Nim にはアロー関数というものがあり、これは通常の関数に対する糖衣構文です。アロー関数を使うには、import sugar
をする必要があります。
上の猫の例をアロー関数を使うように変換してみましょう:
import sugar
type Cat = object
let purr = (this: Cat) => echo "Purr Purr" # `this` を使っている
let dance = (self: Cat) => echo "Tappity Tappity" # `self` を使っている
# 呼び出し構文は同じです
引数を渡す必要がない場合は、渡さないでください:
import sugar
let purr = () => echo "Purr Purr" # 引数なし
purr() # ゴロゴロ
アロー関数にプラグマを使用することができます:
let functionName = () {.inline.} => 42
let another_name = () {.inline.} => 42
(インラインプラグマも参照)
アロー関数に関数名とプラグマを使用することができます:
function_name(argument0, argument1: int) {.noSideEffect.} => argument0 + argument1
let variab = (argument0, argument1: int) {.noSideEffect.} => argument0 + argument1
(noSideEffect プラグマも参照)
コンパイル時の関数実行
Nim はコンパイル時に関数を実行することが可能なので、コンパイル時にバックエンド的なコードを実行し、実行時にフロントエンドで使用することができます。コンパイル時の FFI も可能です。コンパイル時に動作するコードや NimScript のほとんどは、フロントエンドでも動作する傾向があります。
サーバーサイドレンダリング
SCF
Nim Source Code Filters (SCF)は、テンプレートのサーバーサイド描画を行うための標準ライブラリのテンプレート機構です。
SCF は *.nimf
というファイル拡張子を持ち、#?stdtmpl
というシバングで始まります。内部では、ロジックは通常の Nim コードですが、接頭辞に #
が付いており、テンプレートはそのまま(#
なし)で書かれています。
SCF は通常、文字列を返す関数です。これらの関数は通常の文字列操作や書式設定が可能です。これらは通常の Nim コードにコンパイルされ、優れたパフォーマンスを提供します。
#?stdtmpl
#func generateXML(name, age: string): string =
<xml>
<name>$name</name>
<age>$age</age>
</xml>
include "serverside.nimf"
echo generateXML("Nim", "16 (in 2021)")
# prints:
# <xml>
# <name>Nim</name>
# <age>16 (in 2021)</age>
# </xml>
Karax
また、Karax フレームワークはサーバーサイドのレンダリングを行います(nimble install karax
でインストール)。
import karax/[karaxdsl,vdom]
writeFile "app.html", $(block: buildHtml(tdiv):
h1: text"Hello World"
p: text"Compile: nim r file.nim ")
include prelude
import karax / [karaxdsl, vdom]
writeFile "example.html", $(block: buildHtml(tdiv):
link(href="https://cdn.jsdelivr.net/npm/bulma@0.9.1/css/bulma.min.css", rel="stylesheet")
section(class="section"):
tdiv(class="container"):
h1(class="title"):
text"Welcome"
button(class="button is-success"): text"Example"
ol(class="ol"):
li: text"Item 0"
li: text"Item 1"
code(class="code"): text"""echo "Hello World" """
)
クライアントサイドレンダリング
Karax はクライアントサイドレンダリングもできますし、ローカルの開発サーバーも含まれていますし、他にもとても素晴らしいものがあります。
このサンプルは、Karax karun
ツールを使ってウェブブラウザ上でコンパイルし、実行することができます。
include karax/prelude
setRenderer func: auto = buildHtml(h1): text"Hello World"
proc createDom(): VNode =
# クライアントサイドレンダリング
result = buildHtml(tdiv):
# テキストだけ
text "Hello Web Frontend World"
# <aside class="foo" id="bar">
aside(class="foo", id="bar"):
# <img src="cat.png" alt="cat">
img(src="cat.png", alt="cat")
# 属性なしの <span>
span:
# テキストだけ
text "Clickable <button> inside a <span>"
# <button>
button(onclick = () => console.log(""Hi!")):
# テキストだけ
text "Say Hi!"
# いくつかのロジック
for numbeeeeer in 0..9: console.log(number)
# クリックできる <a>
a(onclick = () => console.log("Clicked!"))
# サーバーサイド、ルーティング、バリデーション、イベントなど
setRenderer createDom
Svelte
nclearseam は、Svelte にインスパイアされた Nim フロントエンドです。
Parcel
parcel-plugin-nim は Parcel をサポートするための Nim モジュールです。
CommonJS
jsExport.nimは、CommonJS 対応の Nim モジュールです。
WebGL GUI
nimx は WebGL をターゲットとしたクロスプラットフォームな GUI フレームワークで、GUI を WebGL にコンパイルすることができます。
Electron
Electron の内部で Nim を実行することができます。
Webview
また、クロスプラットフォームの小さな(1 つの .h
ファイル)、高速(C コード)なウェブビューを使用することができます:
- WebGui
- nim 用の Webview
WIISH も同様のクロスプラットフォームな WebView を提供しており、他のターゲットにも対応しています。
React
React.nim は、Nim のための ReactJS バインディングを提供します。
More GUI frameworks
もし、JavaScript のみの GUI であることが必須ではなく、Windows/Linux/Mac で動作する GUI が必要なだけであれば、さらに多くの選択肢を試すことができます:
- nimx
- NimQL
- uibuilder.nim
- wNim
- NiGui
- illwill
- gintro
- UI
- nimgui
WebAssembly
以下のものを使って、Nim のコードを WebAssembly にコンパイルすることができます:
- Clang WASM target OR Emscripten OR NLVM
WebAssembly へのコンパイルの詳細については、こちらをご覧ください:
- NimES
- nlvm
- Nim WebAssembly の例
- wasmrt
Build modes
コードが本番環境に対応できるようになったら、コンパイルコマンドに -d:release
と -d:danger
を追加して、リリースビルドを作成することができます。
特徴 | リリースビルド | デバッグビルド |
---|---|---|
速度 | 高速 | 低速 |
ファイルサイズ | 小さい | 大きい |
最適化 | ✅ | ❌ |
トレースバック | ❌ | ✅ |
ランタイムチェック | ✅ | ✅ |
コンパイル時チェック | ✅ | ✅ |
assert |
❌ | ✅ |
doAssert |
✅ | ✅ |
Minification
Nim はデフォルトでコンパイルされた JavaScript を minify しません 。
Nim は通常、リリース用にビルドする際に非常に小さなファイルサイズにコンパイルします。不要なコード除去のおかげで、使用されるシンボルだけがコンパイルされ、他のシンボルはリリースビルドには存在しません。例えば、あるモジュールをインポートしたが使わなかった場合、リリースビルドには存在しません(ターミナルにヒントが表示され、使われていないインポートがあることが分かります)。
Nim は空白をインデントとして使用します。基本的には Nim がコンパイルした JavaScript ファイルで問題ありません。
あるいは、他の minifier ソフトウェアを使って、JavaScript の後処理をすることもできます。
難読化
Nim はデフォルトでコンパイルされた JavaScript を難読化 しません 。
もし、コンパイルされた JavaScript を難読化したい場合は、{.exportc.}
プラグマを使って名前のマングリングを制御し、難読化として使用することができます。
var variable {.exportc: "lkfnjmgkw3du4905r3q2ep8n4urfp34w2efltgvepotik132qm0".} = false
proc funct() {.exportc: "kl34jgo9liw35e4atr8i30q2rk1fipkpfrsdofir93o2qujfoks".} = echo 42
以下にコンパイルする:
var lkfnjmgkw3du4905r3q2ep8n4urfp34w2efltgvepotik132qm0 = false;
function kl34jgo9liw35e4atr8i30q2rk1fipkpfrsdofir93o2qujfoks() {
rawEcho("42");
}
変数
名や 関数
名といった人間にとって親しみやすい名前を使いながら、コードは難読化された名前にコンパイルされます。
Nim は名前を見失いません。難読化された名前は任意のランダムアルゴリズムで生成できます。
また、他の難読化ソフトウェアを使って、JavaScript の後処理を行うこともできます。
JavaScript の相互接続性
Nim は JavaScript と直接相互に接続することができます。ここでは、独自のライブラリを作成する方法を説明します。
性能面での追加コストはなく、コンパイラはあなたが望むコードを出力するだけです。
できるだけ最小限の例で、あまり有用ではありませんが、できるだけシンプルに説明します:
func log(arg, arg2: SomeNumber) {.importjs: """console.log(#, #)""".}
-
#
は、もしあれば、インデックス0から始まるインデックスごとの引数に置き換えられます。 -
@
は、もしあれば、カンマで区切られた残りのすべての引数で置き換えられます。 - 文字列または Regex の単一の
$
をエスケープするために$$
を使用します。 -
$1
は、現在の関数名で置き換えられます。 - 引数の型と戻り値の型はNimの型、std libの型、または独自のカスタム型です。
-
importcpp
はimportjs
として使われることがあります。 - 関数の戻り値として
openArray
を使うと、seq
の代わりにarray
を返します。 - バニラ JavaScript の
console.log()
などでコンソールに出力する。 - バニラ JavaScript の
(function(){ ...})();
で DOM が準備されていることを確認する。 - バニラ JavaScript の "use strict"; でストリクトモードを強制する。
- ImportJs プラグマ
- 関数に引数がない場合、
@
は何も生成しない(空)。 - 関数に引数がない場合、
#
はエラーを発生させる。 - なお、
@
の場合はカンマが自動的に挿入されますが、#
の場合はカンマを追加する必要があります。 - パターンには複数行の文字列を使用することができます。
- パターンには
strformat
を使用することができますが、strformat
をインポートする必要があります。
この小さな例をJavaScriptのターゲットにコンパイルしてみよう:
func log(arg, arg2: SomeNumber) {.importjs: """console.log(#, #)""".}
log(42, 9)
コンソールで実行する
nim js -d:danger lognumbers.nim
lognumbers.js を生成する
console.log(42, 9);
名前付き引数を使用する必要がある場合は、{.emit.}
プラグマを使用することができます:
func functionName(namedArgument: int) = {.emit: """console.log( `namedArgument`);""".}
相互接続のための有用なプラグマ
- {.importjs.} で JavaScript をインポートする。
- {.compiletime.} コンパイル時にコードを実行するようにします。
- {.exportc.} エスケープ名のマングリング(名前修飾のこと、デバッグや難読化などのため)。
- {.emit.} 渡された引数で直接コードを実行します。
- {.varargs.} 関数に複数の引数を強制的に受け取らせる。
- {.hint.} コードを生成しない、コンパイル時の人間に優しい色付きメッセージ。
- 警告。コードを生成しないコンパイル時に表示される、人間に優しい色のメッセージ。
- {.codegendecl.} コードジェネレータで直接コードを出力します。
- {.noinit.} 暗黙の変数自動初期化を回避する。
- {.discardable.} デバッグ、クイックプロトタイピングなどのために)未使用の戻り値を破棄できるようにする。
- {.noreturn.} 関数が決して返さないように強制する
- {.asmnostackframe.} 関数に結果を持たせないようにします。関数のresultを自動注入しないようにします。
- {.injectStmt.}を使用すると便利です。現在のモジュールの他のすべてのステートメントの前にコードをインジェクトします。
- プラグマは単なるマクロなので、自分で作ることができます。
もっと見る:
- static: / static() コードのブロックをコンパイル時に強制的に実行させる。
- when コンパイル時 if
- 実際のコードの例としては、jsre モジュールがあります。
- jsconsole モジュールで、実際のコード例を見ることができます。
相互接続性テンプレート
- 独自の JavaScript ライブラリを作成するために編集できる Nim の「コードテンプレート」擬似コードです:
func functionName(argument: SomeNumber | string | bool): SomeNumber {.importjs: """
(function () {
"use strict";
console.log("CODE HERE");
console.log(#);
return 42;
})(); """, exportc: "functionName".} ## Documentation Comment.
func functionName2(namedArgument: SomeNumber | string | bool): SomeNumber = {.emit: """
console.log("CODE HERE");
console.log( `namedArgument` );
return 42;
""", exportc: "functionName2".} ## Documentation Comment.
Nim 用 HTML/CSS WYSYWIG エディタ
Spectre CSS
Bulma CSS
NodeJS 互換性
- Nim 用の NodeJS スタンダードライブラリ
その他
ここですべてのドキュメントを重複しないようにするために、こちらを読み進めてください:
Python 向けですが、同じコンセプトでフロントエンドにも使えます!
⬆️ ⬆️ ⬆️ ⬆️