Deno入門 - セキュアなTypeScriptランタイム

入門 | 25分 read | 2025.01.10

Denoとは

DenoはRyan Dahl(Node.js作者)が開発した、セキュアなJavaScript/TypeScriptランタイムです。TypeScriptをネイティブサポートし、デフォルトでセキュアな権限システムを持ちます。

インストール

# macOS / Linux
curl -fsSL https://deno.land/install.sh | sh

# Windows (PowerShell)
irm https://deno.land/install.ps1 | iex

# Homebrew
brew install deno

# バージョン確認
deno --version

基本的な使い方

スクリプト実行

# TypeScriptを直接実行
deno run hello.ts

# URLから直接実行
deno run https://deno.land/std/examples/welcome.ts

# REPLモード
deno

権限システム

# ネットワークアクセス許可
deno run --allow-net server.ts

# ファイル読み込み許可
deno run --allow-read app.ts

# ファイル書き込み許可
deno run --allow-write app.ts

# 環境変数アクセス許可
deno run --allow-env app.ts

# 全権限(開発時のみ)
deno run -A app.ts

# 特定ホストのみ許可
deno run --allow-net=api.example.com app.ts

# 特定ディレクトリのみ許可
deno run --allow-read=/tmp app.ts

HTTPサーバー

標準ライブラリ

// server.ts
import { serve } from "https://deno.land/std@0.220.0/http/server.ts";

const handler = (request: Request): Response => {
  const url = new URL(request.url);

  if (url.pathname === "/") {
    return new Response("Hello, Deno!");
  }

  if (url.pathname === "/api/users") {
    return Response.json([
      { id: 1, name: "Alice" },
      { id: 2, name: "Bob" },
    ]);
  }

  return new Response("Not Found", { status: 404 });
};

console.log("Server running on http://localhost:8000");
serve(handler, { port: 8000 });

Deno.serve(推奨)

// server.ts(Deno 1.35+)
Deno.serve({ port: 8000 }, (request: Request) => {
  const url = new URL(request.url);

  if (url.pathname === "/") {
    return new Response("Hello, Deno!");
  }

  return new Response("Not Found", { status: 404 });
});

Oakフレームワーク

// oak-server.ts
import { Application, Router } from "https://deno.land/x/oak@v12.6.1/mod.ts";

const router = new Router();

router.get("/", (ctx) => {
  ctx.response.body = "Hello, Oak!";
});

router.get("/api/users", (ctx) => {
  ctx.response.body = [
    { id: 1, name: "Alice" },
    { id: 2, name: "Bob" },
  ];
});

router.post("/api/users", async (ctx) => {
  const body = await ctx.request.body().value;
  ctx.response.status = 201;
  ctx.response.body = { created: body };
});

const app = new Application();
app.use(router.routes());
app.use(router.allowedMethods());

console.log("Server running on http://localhost:8000");
await app.listen({ port: 8000 });

ファイル操作

// ファイル読み込み
const text = await Deno.readTextFile("data.txt");
console.log(text);

// JSON読み込み
const json = JSON.parse(await Deno.readTextFile("config.json"));

// バイナリ読み込み
const bytes = await Deno.readFile("image.png");

// ファイル書き込み
await Deno.writeTextFile("output.txt", "Hello, World!");

// JSON書き込み
await Deno.writeTextFile(
  "data.json",
  JSON.stringify({ key: "value" }, null, 2)
);

// ディレクトリ操作
await Deno.mkdir("new-folder", { recursive: true });
await Deno.remove("old-file.txt");

// ファイル情報取得
const stat = await Deno.stat("file.txt");
console.log(stat.size, stat.mtime);

環境変数

// 環境変数の取得
const apiKey = Deno.env.get("API_KEY");
const dbUrl = Deno.env.get("DATABASE_URL") ?? "localhost";

// 全環境変数
const allEnv = Deno.env.toObject();
console.log(allEnv);

// .envファイルの読み込み
import { load } from "https://deno.land/std@0.220.0/dotenv/mod.ts";
const env = await load();
console.log(env.DATABASE_URL);

npm互換性

// npm:プレフィックスでnpmパッケージを使用
import express from "npm:express@4";
import _ from "npm:lodash";

const app = express();

app.get("/", (req, res) => {
  res.send("Hello from Express on Deno!");
});

app.listen(3000);
// deno.json
{
  "imports": {
    "express": "npm:express@4",
    "lodash": "npm:lodash@4"
  }
}

Import Maps

// deno.json
{
  "imports": {
    "@std/": "https://deno.land/std@0.220.0/",
    "oak": "https://deno.land/x/oak@v12.6.1/mod.ts",
    "zod": "https://deno.land/x/zod@v3.22.4/mod.ts"
  }
}
// エイリアスで簡潔に
import { serve } from "@std/http/server.ts";
import { Application } from "oak";
import { z } from "zod";

テスト

// sum.test.ts
import { assertEquals, assertThrows } from "https://deno.land/std@0.220.0/assert/mod.ts";
import { sum, divide } from "./sum.ts";

Deno.test("sum adds two numbers", () => {
  assertEquals(sum(1, 2), 3);
});

Deno.test("sum handles negative numbers", () => {
  assertEquals(sum(-1, 1), 0);
});

Deno.test("divide throws on zero", () => {
  assertThrows(
    () => divide(10, 0),
    Error,
    "Division by zero"
  );
});

// 非同期テスト
Deno.test("fetch data", async () => {
  const response = await fetch("https://api.example.com/data");
  assertEquals(response.status, 200);
});
# テスト実行
deno test

# 特定ファイル
deno test sum.test.ts

# ウォッチモード
deno test --watch

# カバレッジ
deno test --coverage=coverage
deno coverage coverage

タスクランナー

// deno.json
{
  "tasks": {
    "dev": "deno run --watch --allow-net server.ts",
    "start": "deno run --allow-net server.ts",
    "test": "deno test --allow-read",
    "lint": "deno lint",
    "fmt": "deno fmt"
  }
}
deno task dev
deno task test

コンパイル

# 単一実行ファイルにコンパイル
deno compile --allow-net server.ts

# クロスコンパイル
deno compile --target x86_64-unknown-linux-gnu server.ts
deno compile --target x86_64-apple-darwin server.ts
deno compile --target x86_64-pc-windows-msvc server.ts

Node.jsとの違い

特徴DenoNode.js
TypeScriptネイティブサポート要トランスパイル
セキュリティデフォルトでセキュア制限なし
パッケージ管理URLインポート/npm:npm/yarn
設定ファイルdeno.json(オプション)package.json必須
標準ライブラリ充実最小限
ES ModulesデフォルトCommonJS中心

関連記事

まとめ

Denoは、セキュリティとTypeScriptサポートを重視したモダンなランタイムです。権限システムにより安全な実行環境を提供し、npm互換性により既存のエコシステムも活用できます。

← Back to list