ข้ามไปยังเนื้อหา

AssemblyScript

AssemblyScript คือคอมไพเลอร์ที่แปลง TypeScript Subset ที่เข้มงวด ให้เป็น WebAssembly ถ้าคุณรู้จัก TypeScript อยู่แล้ว คุณสามารถเริ่มใช้ AssemblyScript ได้ในไม่กี่นาที ไม่มี Borrow Checker ของ Rust ไม่มีการจัดการ Memory แบบ C — เพียงแค่ TypeScript ที่มี Type และ Annotation เฉพาะของ Wasm

Terminal window
# สร้างโปรเจกต์ Node.js ใหม่
mkdir as-demo && cd as-demo
npm init -y
# ติดตั้งคอมไพเลอร์ AssemblyScript
npm install --save-dev assemblyscript
# สร้างโครงสร้างโปรเจกต์ (สร้าง assembly/ และ tsconfig.json)
npx asinit .

ไดเรกทอรี assembly/ เก็บไฟล์ Source .ts ของคุณ และ asconfig.json กำหนดค่าคอมไพเลอร์

เปิด assembly/index.ts:

// การบวกเลขจำนวนเต็ม — สังเกตประเภท i32 ที่ระบุชัดเจน
export function add(a: i32, b: i32): i32 {
return a + b;
}
// Factorial — แบบ Recursive, ใช้ i64 เพื่อป้องกัน Overflow สำหรับ Input ขนาดใหญ่
export function factorial(n: i64): i64 {
if (n <= 1) return 1;
return n * factorial(n - 1);
}
// Clamp ค่า Float ระหว่าง lo และ hi
export function clamp(value: f64, lo: f64, hi: f64): f64 {
if (value < lo) return lo;
if (value > hi) return hi;
return value;
}

ความแตกต่างหลักจาก TypeScript ทั่วไป:

  • Type อย่าง i32, i64, f32, f64 คือ Numeric Type ของ Wasm ไม่ใช่ number ของ TypeScript
  • ไม่มี any, ไม่มี unknown และไม่มีการแปลง Type โดยอัตโนมัติ
  • export ทำให้ฟังก์ชันเข้าถึงได้จาก JavaScript (เหมือน (export ...) ใน WAT)
Terminal window
# Development Build (อ่านได้ง่าย, ไม่ Optimise)
npx asc assembly/index.ts --outFile build/release.wasm --textFile build/release.wat
# Release Build (Optimise แล้ว, Binary เล็กกว่า)
npx asc assembly/index.ts --outFile build/release.wasm --optimize
# พร้อม Binding สำหรับใช้เป็น ES Module
npx asc assembly/index.ts --outFile build/release.wasm --bindings esm
// ใช้ @assemblyscript/loader Helper
import { instantiateStreaming } from '@assemblyscript/loader';
const { exports } = await instantiateStreaming(fetch('./build/release.wasm'));
console.log(exports.add(10, 32)); // 42
console.log(exports.factorial(BigInt(10))); // 3628800n (i64 → BigInt)
console.log(exports.clamp(1.5, 0.0, 1.0)); // 1

หรือใช้ WebAssembly API โดยตรงโดยไม่ต้องใช้ Loader:

const response = await fetch('./build/release.wasm');
const bytes = await response.arrayBuffer();
const { instance } = await WebAssembly.instantiate(bytes, {});
console.log(instance.exports.add(3, 4)); // 7

Editor ด้านล่างเปิดโปรเจกต์ AssemblyScript ใน StackBlitz ที่คุณสามารถแก้ไข คอมไพล์ และรันโค้ดใน browser ได้โดยตรง

AssemblyScript

Needs the AssemblyScript toolchain — open in StackBlitz to build & run.

ตัวเลือกBenefitCost
AssemblyScriptSyntax คุ้นเคยสำหรับคนที่เขียน TypeScript อยู่แล้ว เริ่มต้นได้เร็ว ไม่มี GC หรือ Runtime OverheadEcosystem จำกัดมากเมื่อเทียบกับ Rust หรือ C และ ไม่ semantically เหมือน TypeScript ทุกจุด — Type System และ Feature Set ต่างกัน
Rust + wasm-bindgenMemory Safety จาก Ownership Model, Binary Size เล็ก, Ecosystem ใหญ่กว่าLearning Curve สูงกว่ามากสำหรับทีมที่ไม่เคยเขียน Rust (Ownership/Borrowing)
  • คิดว่า AssemblyScript คือ TypeScript เต็มรูปแบบ แล้วใช้ Feature ที่ TS รองรับแต่ asc ไม่รองรับ (เช่น Union Type ซับซ้อน หรือ any) จนเจอ Compile Error ที่ไม่คาดคิด
  • ลืมว่า number ของ TypeScript ไม่มีอยู่จริงใน AssemblyScript ต้องระบุ i32/i64/f32/f64 ให้ชัดเจนเสมอ
  • เลือก AssemblyScript สำหรับงานที่ต้องพึ่ง Library จำนวนมาก (เช่น Image Processing ที่ซับซ้อน) โดยไม่เช็ค Ecosystem ก่อน จนต้องเขียน Logic เองใหม่ทั้งหมด

💡 ตัวอย่างจากของจริง

NEAR Protocol ใช้ AssemblyScript เป็นหนึ่งในภาษาหลักสำหรับเขียน Smart Contract ที่คอมไพล์เป็น Wasm และ Shopify Functions ก็รองรับ AssemblyScript เป็นตัวเลือกให้ Merchant เขียน Custom Checkout Logic ควบคู่กับ Rust

AssemblyScript ใช้ Numeric Type ใดสำหรับเลขจำนวนเต็ม 32 บิต?
จะทำให้ฟังก์ชัน AssemblyScript เรียกได้จาก JavaScript ได้อย่างไร?
'npx asinit .' ทำอะไรเมื่อสร้าง Scaffolding โปรเจกต์ AssemblyScript?
ทำไม AssemblyScript จึงผลิต Wasm Binary ขนาดเล็ก?