You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在io-ts库中使用@types/fabric预定义接口实现运行时类型检查?

Using @types/fabric Interfaces with io-ts for Runtime Type Checking

The core issue you're hitting is that TypeScript interfaces are compile-only constructs—they don't exist in runtime, so io-ts can't use them directly for validation. The example from io-ts issue #209 references generating io-ts codecs from TypeScript types (not raw interfaces), which requires mapping fabric's pre-defined types to runtime-validatable io-ts structures. Here's how to make this work:

Solution: Map Fabric Interfaces to io-ts Codecs

Since you can't pass interfaces directly to io-ts, you need to create io-ts Codec instances that mirror the structure of fabric's ICircleOptions, IRectOptions, and other shapes. Here's a step-by-step implementation:

1. Define Base Fabric Object Properties

First, create a partial codec for properties shared across most fabric objects (since ICircleOptions and IRectOptions inherit from base fabric interfaces):

import * as t from 'io-ts';
import type { ICircleOptions, IRectOptions } from 'fabric';

// Partial codec for shared fabric object options (adjust based on your validation needs)
const BaseFabricObject = t.partial({
  left: t.number,
  top: t.number,
  fill: t.string,
  stroke: t.string,
  strokeWidth: t.number,
  opacity: t.number,
  selectable: t.boolean,
  // Add any other properties you need to validate
});

2. Create Codecs for Specific Fabric Shapes

Combine the base properties with shape-specific fields, and add a type literal to help io-ts distinguish between shapes during validation:

// Codec mirroring ICircleOptions
const CircleOptions = t.intersection([
  BaseFabricObject,
  t.type({
    type: t.literal('circle'), // Explicit type marker for union discrimination
    radius: t.number,
  }),
]);

// Codec mirroring IRectOptions
const RectOptions = t.intersection([
  BaseFabricObject,
  t.type({
    type: t.literal('rect'),
    width: t.number,
    height: t.number,
  }),
]);

3. Build Your Final Response Codec

Now you can use these shape codecs in your Response definition:

const Response = t.type({
  id: t.number,
  type: t.string,
  objects: t.array(t.union([CircleOptions, RectOptions])),
});

// Optional: Get the TypeScript type from the codec for compile-time safety
type ResponseType = t.TypeOf<typeof Response>;

4. Validate Data at Runtime

Use io-ts's decode method to validate incoming data:

const sampleData = {
  id: 1,
  type: 'canvas',
  objects: [
    { type: 'circle', radius: 50, fill: 'red', left: 100 },
    { type: 'rect', width: 200, height: 100, stroke: 'blue' }
  ]
};

const result = Response.decode(sampleData);

if (result._tag === 'Right') {
  // Valid data: result.right is typed as ResponseType
  console.log('Valid data:', result.right);
} else {
  // Invalid data: result.left contains detailed error messages
  console.error('Validation failed:', result.left);
}

Alternative: Auto-Generate Codecs (Advanced)

If you don't want to manually map every fabric interface, use these tools to auto-generate codecs:

  • io-ts-codegen: Generate io-ts code from TypeScript type definitions (extract the fabric types you need into a separate file first).
  • ts-json-schema-generator: Convert TypeScript interfaces to JSON Schema, then use io-ts-from-schema to generate codecs from the schema.

Note that auto-generation may require tweaks, as fabric's type definitions are complex and include optional/union types that need special handling.


内容的提问来源于stack exchange,提问作者Abhishek T.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 05:47:39