型定義
md2formは完全にTypeScriptで書かれており、型安全なフォーム処理を可能にします。このページでは、すべての型定義について詳しく説明します。
主要な型
FormDocument
パースされたフォーム全体を表すメインの型です。
type FormDocument = {
title: string // フォームタイトル(必須)
description?: string // フォーム説明文(任意)
settings?: FormSettings // フォーム設定(任意)
pages: Page[] // ページ(セクション)の配列
}使用例:
import { parseMarkdownToForm } from "md2form"
import type { FormDocument } from "md2form"
const form: FormDocument = await parseMarkdownToForm(markdown)
console.log(form.title) // string
console.log(form.pages.length) // numberFormSettings
フロントマターで設定されるフォーム全体の設定を表す型です。
type FormSettings = {
collectEmail?: boolean // メールアドレス収集
allowMultipleResponses?: boolean // 複数回答許可
limitResponses?: number | null // 回答数制限
showProgressBar?: boolean // プログレスバー表示
shuffleQuestions?: boolean // 質問順シャッフル
themeColor?: string // テーマカラー
backgroundImage?: string // 背景画像
font?: string // フォント
responseReceipt?: "always" | "never" | "whenRequested" // 受領通知
}Page
フォーム内の1つのページ(セクション)を表す型です。
type Page = {
title?: string // ページタイトル(任意)
description?: string // ページ説明(任意)
elements: FormElement[] // 質問要素の配列
}FormElementBase
すべての質問要素が共通して持つ基本プロパティです。
type FormElementBase = {
type: ElementType // 質問タイプ(必須)
label?: string // 質問ラベル(任意)
description?: string // 質問説明(任意)
required?: boolean // 必須入力フラグ(任意)
visible?: boolean // 表示フラグ(任意)
}質問タイプの列挙型
type ElementType =
| "short_text" // 短いテキスト入力
| "long_text" // 長いテキスト入力
| "number" // 数値入力
| "email" // メールアドレス入力
| "phone" // 電話番号入力
| "dropdown" // ドロップダウン選択
| "radio" // ラジオボタン選択
| "checkbox" // チェックボックス選択
| "date" // 日付選択
| "time" // 時刻選択
| "rating" // 星評価
| "likert" // リッカート尺度
| "matrix" // マトリクス(格子)
| "file_upload" // ファイルアップロード
| "section_header" // セクションヘッダー
| "scale" // スケール(スライダー)
| "signature" // 電子署名
| "image" // 画像表示
| "video" // 動画表示
| "boolean" // Yes/No選択
| "unknown" // 不明なタイプ(フォールバック)FormElement ユニオン型
すべての質問要素を含むユニオン型です。
type FormElement =
| ShortText
| LongText
| NumberField
| EmailField
| PhoneField
| DropdownField
| RadioField
| CheckboxField
| DateField
| TimeField
| RatingField
| LikertField
| MatrixField
| FileUploadField
| SectionHeader
| ScaleField
| SignatureField
| MediaField
| BooleanField
| UnknownElement詳細な質問タイプ定義
テキスト入力系
ShortText
type ShortText = FormElementBase & {
type: "short_text"
placeholder?: string // プレースホルダー
maxLength?: number // 最大文字数
default?: string // デフォルト値
}LongText
type LongText = FormElementBase & {
type: "long_text"
placeholder?: string // プレースホルダー
maxLength?: number // 最大文字数
default?: string // デフォルト値
richText?: boolean // リッチテキスト編集
}NumberField
type NumberField = FormElementBase & {
type: "number"
placeholder?: string // プレースホルダー
min?: number // 最小値
max?: number // 最大値
step?: number // 刻み値
default?: number | null // デフォルト値
integerOnly?: boolean // 整数のみ許可
}EmailField
type EmailField = FormElementBase & {
type: "email"
placeholder?: string // プレースホルダー
default?: string // デフォルト値
allowMultiple?: boolean // 複数メールアドレス許可
}PhoneField
type PhoneField = FormElementBase & {
type: "phone"
placeholder?: string // プレースホルダー
countryCodeRequired?: boolean // 国コード必須
default?: string // デフォルト値
}選択系
DropdownField
type DropdownField = FormElementBase & {
type: "dropdown"
options: string[] // 選択肢
allowOther?: boolean // その他選択肢許可
multiple?: false // 複数選択(常にfalse)
default?: string | null // デフォルト選択値
searchable?: boolean // 検索機能有効化
}RadioField
type RadioField = FormElementBase & {
type: "radio"
options: string[] // 選択肢
allowOther?: boolean // その他選択肢許可
default?: string | null // デフォルト選択値
}CheckboxField
type CheckboxField = FormElementBase & {
type: "checkbox"
options: string[] // 選択肢
minSelected?: number | null // 最小選択数
maxSelected?: number | null // 最大選択数
default?: string[] | null // デフォルト選択値配列
}日時系
DateField
type DateField = FormElementBase & {
type: "date"
includeTime?: boolean // 時刻も含めるか
minDate?: string // 最小日付(ISO形式)
maxDate?: string // 最大日付(ISO形式)
default?: string | null // デフォルト日付
}TimeField
type TimeField = FormElementBase & {
type: "time"
minTime?: string // 最小時刻(HH:MM)
maxTime?: string // 最大時刻(HH:MM)
stepMinutes?: number // 刻み幅(分)
default?: string | null // デフォルト時刻
}評価・スケール系
RatingField
type RatingField = FormElementBase & {
type: "rating"
scale?: number // 評価段階数
labels?: { low?: string; high?: string } // 最低・最高ラベル
default?: number | null // デフォルト評価
icon?: "star" | "heart" | "circle" // アイコンタイプ
}LikertField
type LikertField = FormElementBase & {
type: "likert"
statements: string[] // 評価項目(行)
scaleLabels: string[] // 評価尺度(列)
requiredPerStatement?: boolean // 各項目必須評価
}MatrixField
type MatrixField = FormElementBase & {
type: "matrix"
rows: string[] // 行ラベル
columns: string[] // 列ラベル
cellType?: "radio" | "checkbox" | "number" | "short_text" // セルタイプ
requiredPerRow?: boolean // 各行必須入力
}ScaleField
type ScaleField = FormElementBase & {
type: "scale"
min: number // 最小値
max: number // 最大値
step?: number // 刻み値
minLabel?: string // 最小値ラベル
maxLabel?: string // 最大値ラベル
default?: number | null // デフォルト値
}ファイル・署名系
FileUploadField
type FileUploadField = FormElementBase & {
type: "file_upload"
allowedTypes?: string[] // 許可ファイル形式
maxFiles?: number // 最大ファイル数
maxSizeMB?: number // 最大サイズ(MB)
}SignatureField
type SignatureField = FormElementBase & {
type: "signature"
captureMode?: "draw" | "type" | "upload" // 署名方法
required?: boolean // 必須署名
}メディア・表示系
MediaField
type MediaField = FormElementBase & {
type: "image" | "video"
src: string // メディアURL
alt?: string // 代替テキスト(imageのみ)
width?: number | "auto" // 幅
height?: number | "auto" // 高さ
caption?: string // キャプション
}SectionHeader
type SectionHeader = FormElementBase & {
type: "section_header"
title?: string // メインタイトル
subtitle?: string // サブタイトル
}その他
BooleanField
type BooleanField = FormElementBase & {
type: "boolean"
onLabel?: string // Trueの場合のラベル
offLabel?: string // Falseの場合のラベル
default?: boolean | null // デフォルト値
}UnknownElement
type UnknownElement = FormElementBase & {
type: "unknown" // 不明なタイプのフォールバック
}便利な型エイリアス
TextInputElement
テキスト入力系要素のユニオン型:
type TextInputElement = ShortText | LongText | NumberField | EmailField | PhoneField型ガードの実装
TypeScriptで型安全にフォーム要素を処理するための型ガード関数:
import type { FormElement, ShortText, NumberField, RatingField } from "md2form"
// 基本的な型ガード
function isShortText(element: FormElement): element is ShortText {
return element.type === "short_text"
}
function isNumberField(element: FormElement): element is NumberField {
return element.type === "number"
}
function isRatingField(element: FormElement): element is RatingField {
return element.type === "rating"
}
// 汎用的な型ガード
function isElementOfType<T extends FormElement>(
element: FormElement,
type: T["type"],
): element is T {
return element.type === type
}
// 使用例
form.pages.forEach((page) => {
page.elements.forEach((element) => {
if (isShortText(element)) {
console.log(element.placeholder) // 型安全
}
if (isElementOfType<NumberField>(element, "number")) {
console.log(element.min, element.max) // 型安全
}
})
})実践的な型活用例
型安全なフォーム処理
import { parseMarkdownToForm } from "md2form"
import type { FormDocument, FormElement, ShortText, NumberField, CheckboxField } from "md2form"
// フォーム処理クラス
class FormProcessor {
private form: FormDocument
constructor(form: FormDocument) {
this.form = form
}
// 型安全な要素抽出
getElementsByType<T extends FormElement>(type: T["type"]): T[] {
const elements: T[] = []
this.form.pages.forEach((page) => {
page.elements.forEach((element) => {
if (element.type === type) {
elements.push(element as T)
}
})
})
return elements
}
// 必須質問の取得
getRequiredElements(): FormElement[] {
const required: FormElement[] = []
this.form.pages.forEach((page) => {
page.elements.forEach((element) => {
if (element.required) {
required.push(element)
}
})
})
return required
}
// 統計情報の取得
getStatistics(): {
totalElements: number
requiredElements: number
elementTypeCount: Record<string, number>
} {
let totalElements = 0
let requiredElements = 0
const elementTypeCount: Record<string, number> = {}
this.form.pages.forEach((page) => {
page.elements.forEach((element) => {
totalElements++
if (element.required) {
requiredElements++
}
elementTypeCount[element.type] = (elementTypeCount[element.type] || 0) + 1
})
})
return {
totalElements,
requiredElements,
elementTypeCount,
}
}
}バリデーション関数
import type { FormElement, ShortText, LongText, NumberField, CheckboxField } from "md2form"
// 型安全なバリデーション関数
function validateFormElement(element: FormElement): string[] {
const errors: string[] = []
// 共通バリデーション
if (element.required && !element.label) {
errors.push("必須質問にはラベルが必要です")
}
// 型別バリデーション
switch (element.type) {
case "short_text":
case "long_text":
const textElement = element as ShortText | LongText
if (textElement.maxLength && textElement.maxLength <= 0) {
errors.push("maxLengthは正の値である必要があります")
}
break
case "number":
const numberElement = element as NumberField
if (
numberElement.min !== undefined &&
numberElement.max !== undefined &&
numberElement.min > numberElement.max
) {
errors.push("最小値は最大値以下である必要があります")
}
break
case "checkbox":
const checkboxElement = element as CheckboxField
if (checkboxElement.options.length === 0) {
errors.push("チェックボックスには選択肢が必要です")
}
if (
checkboxElement.maxSelected &&
checkboxElement.maxSelected > checkboxElement.options.length
) {
errors.push("最大選択数は選択肢数以下である必要があります")
}
break
}
return errors
}カスタム型の拡張
import type { FormSettings, FormDocument } from "md2form"
// カスタム設定型の拡張
interface ExtendedFormSettings extends FormSettings {
customBranding?: {
logo?: string
primaryColor?: string
secondaryColor?: string
}
analytics?: {
trackingId?: string
enableHeatmap?: boolean
}
}
// 拡張されたフォーム文書型
interface ExtendedFormDocument extends Omit<FormDocument, "settings"> {
settings?: ExtendedFormSettings
}
// 使用例
function processExtendedForm(form: ExtendedFormDocument) {
console.log(form.title)
if (form.settings?.customBranding?.logo) {
console.log("ロゴ:", form.settings.customBranding.logo)
}
if (form.settings?.analytics?.trackingId) {
console.log("トラッキングID:", form.settings.analytics.trackingId)
}
}型定義の利点
1. 開発時の安全性
import type { ShortText } from "md2form"
// コンパイル時にエラーを検出
const element: ShortText = {
type: "short_text",
label: "お名前",
maxLenght: 100, // ❌ タイプミス - コンパイルエラー
}
// 正しい記述
const element: ShortText = {
type: "short_text",
label: "お名前",
maxLength: 100, // ✅ 正しい
}2. IntelliSenseサポート
IDEで自動補完とドキュメントが利用できます。
3. リファクタリングの安全性
型定義により、大規模な変更時も安全にリファクタリングできます。
JSON型定義(補足)
src/types/json.types.tsには、JSON処理に関連する補助型が定義されています。これらもmd2formから直接インポート可能です:
import type { JsonValue, JsonObject, JsonArray } from "md2form"
// JSON値の型定義
type JsonValue = string | number | boolean | null | JsonObject | JsonArray
interface JsonObject {
[key: string]: JsonValue
}
interface JsonArray extends Array<JsonValue> {}
// フォームデータのJSON変換用型
type SerializableFormDocument = Omit<FormDocument, "pages"> & {
pages: SerializableJsonObject[]
}型定義のベストプラクティス
1. 明示的な型注釈
import { parseMarkdownToForm } from "md2form"
import type { FormDocument } from "md2form"
// ❌ 型推論に依存
const form = await parseMarkdownToForm(markdown)
// ✅ 明示的な型指定
const form: FormDocument = await parseMarkdownToForm(markdown)2. 型ガードの活用
import type { ShortText } from "md2form"
// ❌ 型キャストに依存
const shortText = element as ShortText
console.log(shortText.maxLength)
// ✅ 型ガードを使用
if (isShortText(element)) {
console.log(element.maxLength) // 型安全
}3. ユニオン型の適切な処理
import type { FormElement } from "md2form"
// ✅ discriminated unionの活用
function processElement(element: FormElement) {
switch (element.type) {
case "short_text":
// この時点でelementはShortText型
console.log(element.maxLength)
break
case "number":
// この時点でelementはNumberField型
console.log(element.min, element.max)
break
// ... その他のcase
}
}次のステップ
型定義を理解したら、以下のページでさらに詳細な情報を確認してください:
- API リファレンス - 関数とクラスの詳細
- 実装例 - TypeScriptでの実際の使用例
- 基本的な使い方 - 型安全なパース処理の基本