Superstruct

バリデーションライブラリJavaScriptTypeScriptスキーマデータ検証ランタイム

ライブラリ

Superstruct

概要

Superstructは「Simple and composable way to validate data in JavaScript (and TypeScript)」として開発された軽量で柔軟なバリデーションライブラリです。TypeScript、Flow、Go、GraphQLからインスピレーションを受けたAPI設計により、直感的でシンプルなデータ構造定義を可能にします。モジュラー設計とカスタマイズ性に優れ、アプリケーション固有の要件に完全に適応可能。2025年現在、軽量性と拡張性を重視する開発者に選ばれているバリデーションライブラリです。

詳細

Superstruct 1.0は2025年現在の最新安定版で、シンプルさと構成可能性を重視した設計哲学を採用しています。他のバリデーションライブラリとは異なり、コア機能を最小限に抑え、すべてのカスタマイゼーションをユーザーに委ねる設計。13k+のGitHubスターを獲得し、特にTypeScriptプロジェクトでの軽量な代替選択肢として注目されています。ランタイムでの詳細なエラー情報提供により、エンドユーザー向けアプリケーションに最適。

主な特徴

  • 軽量設計: 最小限のコア機能でバンドルサイズを削減
  • 完全カスタマイズ可能: アプリケーション固有の型定義に完全対応
  • TypeScript統合: 型推論とランタイム検証の両立
  • 構成可能なAPI: シンプルなビルディングブロックから複雑なスキーマを構築
  • 詳細なエラー報告: デバッグとユーザー体験を向上させる詳細なエラー情報
  • デフォルト値サポート: データ変換と初期値設定の統合

メリット・デメリット

メリット

  • シンプルで直感的なAPI設計
  • 他ライブラリより軽量でバンドルサイズが小さい
  • アプリケーション要件への完全なカスタマイズ性
  • TypeScriptとJavaScriptの両方で利用可能
  • 詳細なエラーメッセージでデバッグが容易
  • 関数型プログラミングスタイルをサポート

デメリット

  • Zodと比較して型推論機能が限定的
  • コミュニティエコシステムが小規模
  • 高度な機能には追加実装が必要
  • 学習リソースが比較的少ない
  • 企業レベルでの採用事例が限定的
  • 複雑なバリデーションには冗長な記述が必要

参考ページ

書き方の例

インストールと基本セットアップ

# npmを使用
npm install superstruct

# yarnを使用
yarn add superstruct

# pnpmを使用
pnpm add superstruct

基本的なデータ検証

import { assert, object, number, string, array } from 'superstruct'

// 記事スキーマの定義
const Article = object({
  id: number(),
  title: string(),
  tags: array(string()),
  author: object({
    id: number(),
    name: string(),
  }),
})

// データの検証
const data = {
  id: 34,
  title: 'Hello World',
  tags: ['news', 'features'],
  author: {
    id: 1,
    name: 'John Doe',
  },
}

try {
  assert(data, Article)
  console.log('データは有効です')
} catch (error) {
  console.error('バリデーションエラー:', error.message)
}

TypeScriptでの型推論

import { type, object, string, number, Infer } from 'superstruct'

// ユーザースキーマの定義
const User = object({
  name: string(),
  age: number(),
  email: string(),
})

// TypeScript型の推論
type UserType = Infer<typeof User>
// UserType = { name: string; age: number; email: string }

// 関数での利用
function createUser(userData: unknown): UserType {
  return type(userData, User)
}

カスタムバリデーションの実装

import { define, string } from 'superstruct'

// カスタムバリデーター: メールアドレス
const Email = define('Email', (value) => {
  return typeof value === 'string' && /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value)
})

// カスタムバリデーター: 強力なパスワード
const StrongPassword = define('StrongPassword', (value) => {
  return (
    typeof value === 'string' &&
    value.length >= 8 &&
    /(?=.*[a-z])(?=.*[A-Z])(?=.*\d)/.test(value)
  )
})

// 使用例
const UserRegistration = object({
  email: Email,
  password: StrongPassword,
  name: string(),
})

デフォルト値とデータ変換

import { create, object, string, number, defaulted } from 'superstruct'

// デフォルト値付きスキーマ
const UserProfile = object({
  id: defaulted(number(), () => Math.floor(Math.random() * 1000000)),
  name: string(),
  role: defaulted(string(), 'user'),
  createdAt: defaulted(string(), () => new Date().toISOString()),
})

// データの作成と変換
const inputData = { name: 'Alice' }
const user = create(inputData, UserProfile)

console.log(user)
// {
//   id: 123456,
//   name: 'Alice',
//   role: 'user',
//   createdAt: '2025-06-22T10:30:00.000Z'
// }

エラーハンドリングとバリデーション結果

import { validate, object, string, number } from 'superstruct'

const PersonSchema = object({
  name: string(),
  age: number(),
})

// バリデーション結果の取得
const [error, result] = validate(data, PersonSchema)

if (error) {
  console.error('検証失敗:', error.message)
  console.error('詳細:', error.failures())
} else {
  console.log('検証成功:', result)
}

複雑なネストしたオブジェクトの検証

import { object, string, number, array, optional, union } from 'superstruct'

const CompanySchema = object({
  name: string(),
  founded: number(),
  employees: array(object({
    id: number(),
    name: string(),
    position: string(),
    salary: optional(number()),
    department: union([
      string(),
      object({
        name: string(),
        budget: number(),
      })
    ]),
  })),
  headquarters: object({
    address: string(),
    city: string(),
    country: string(),
  }),
})

// 複雑なデータ構造の検証
const companyData = {
  name: 'Tech Corp',
  founded: 2020,
  employees: [
    {
      id: 1,
      name: 'Alice Johnson',
      position: 'Engineer',
      salary: 75000,
      department: 'Engineering',
    },
    {
      id: 2,
      name: 'Bob Smith',
      position: 'Manager',
      department: {
        name: 'Sales',
        budget: 500000,
      },
    },
  ],
  headquarters: {
    address: '123 Tech Street',
    city: 'San Francisco',
    country: 'USA',
  },
}

assert(companyData, CompanySchema)

その他

Superstructは軽量性とシンプルさを重視するプロジェクトに最適です。特に、カスタムバリデーションロジックが多く必要な場合や、バンドルサイズを最小限に抑えたい場合に優れた選択肢となります。TypeScriptプロジェクトでは型推論の恩恵を受けながら、JavaScriptプロジェクトでもシンプルなAPIを活用できる柔軟性が特徴です。