le0daniel/typescript-schema

1.0.2 2024-07-17 14:23 UTC

This package is auto-updated.

Last update: 2024-09-25 21:58:21 UTC


README

这是一个简单的库,没有外部依赖,可以从您定义的模式生成 TypeScript 模式。这可以帮助您在不使用 GraphQL 或类似工具的情况下创建严格的 REST API 输入和输出合约。

该库深受 GraphQL 和 Zod 的启发。它首先解析,然后验证和转换。

安装

composer require le0daniel/typescript-schema

入门指南

定义输入或输出的模式。

use TypescriptSchema\Schema;

$user = Schema::object([
    'name' => Schema::string()->nonEmpty()->min(1)->max(255),
    'email' => Schema::string()->email()->endsWith('.com')
]);

$user->toDefinition()->input // {name: string, email: string}
$user->toDefinition()->output // {name: string, email: string}

$user->parse(['name' => 'The name', 'email' => 'email@test.com', 'other']) // ['name' => 'The name', 'email' => 'email@test.com']
$result = $user->safeParse([/* unsafe input */])

$result->isSuccess();
$result->getData(); // Returns the data on success or null on failure.

基本类型

  • 字符串 Schema::string() | StringType::make()
  • 整数 Schema::float() | FloatType::make()
  • 浮点数 Schema::float() | FloatType::make()
  • 布尔值 Schema::boolean() | BoolType::make()
  • 文字 Schema::literal('book') | LiteralType::make('book')
  • 日期时间 Schema::dateTime(format) | DateTimeType::make(format)
  • 未知 Schema::unknown() | UnknownType::make()
  • 任何 Schema::any() | AnyType::make()
  • 枚举 Schema::enum(class) | EnumType::make(class)

值的强制转换

默认情况下,类型检查是严格的。这意味着将数字传递给字符串类型将导致失败。您可以使用强制转换来使其不那么严格,如下所示:Schema::string()->coerce()。这适用于所有基本类型。

对于不同的基本类型,它的工作方式如下:

  • 字符串:(string) $value
  • 整数:(int) $value
  • 浮点数:(float) $value
  • 布尔值:接受 0、1、'0'、'1'、'true'、'false'
  • 枚举:接受受支持的枚举值。
  • 日期时间:行为无变化
  • 文字:行为无变化。
  • 任何:行为无变化。
  • 未知:行为无变化。

字符串

字符串类型支持以下默认验证

  • 最小值(包括最小字符数) Schema::string()->min(5)
  • 最大值(包括最大字符数) Schema::string()->max(5)
  • 以...结尾 Schema::string()->endsWith('.test')
  • 以...开头 Schema::string()->startsWith('Hello: ')
  • 非空 Schema::string()->notEmpty()
  • 正则表达式 Schema::string()->regex('/[a-z]+/')
  • 字母数字 Schema::string()->alphaNumeric()
  • 电子邮件 Schema::string()->email()

以下转换器可用

  • 删除空格 Schema::string()->trim()
  • 小写 Schema::string()->lowerCase()
  • 大写 Schema::string()->upperCase()

整数

整数类型支持以下验证

  • 最小值(包括) Schema::int()->min(5)
  • 最大值(包括) Schema::int()->max(5)

日期时间

DateTime 原始类型默认接受字符串(在给定格式中,默认为 DateTime::ATOM)或 DateTimeInterface 的实例。所有实例都转换为 DateTimeImmutable。

默认输出类型如下: {date: string, timezone_type: number, timezone: string}。这是 PHP 中 DateTime 类的默认 JsonSerialization。

对于输出,使用 Schema::dateTime()->asFormattedString() 很有用,这将返回格式化的字符串而不是 DateTimeImmutableInstance。

枚举

枚举类型期望输入是枚举实例或枚举名称的字符串。

use TypescriptSchema\Schema;
use TypescriptSchema\Exceptions\ParsingException;

enum MyEnum {
    case SUCCESS;
    case FAILURE;
}

$type = Schema::enum(MyEnum::class);

$type->toDefinition()->input                // => 'SUCCESS'|'FAILURE'
$type->toDefinition()->output               // => never
$type->asString()->toDefinition()->output   // => 'SUCCESS'|'FAILURE'

// Parsing always returns the Enum case itself.
$type->parse(MyEnum::SUCCESS) // => MyEnum::SUCCESS
$type->parse('SUCCESS') // => MyEnum::SUCCESS

// Parsing as strings always returns the string with the enum name.
$type->asString()->parse('SUCCESS') // => 'SUCCESS'
$type->asString()->parse(MyEnum::SUCCESS) // => 'SUCCESS'

由于 PHP 中的 UnitEnums 无法进行 Json 序列化,未受支持的枚举的默认输出类型为 never。使用枚举时,请考虑使用 asString() 转换器以获得一致的 JSON 响应输出。

受支持枚举的行为

受支持的枚举可以序列化为 Json,因此输出类型为 literals<number>|literals<string>

示例

use TypescriptSchema\Schema;

enum MyEnum: string {
    case SUCCESS = 'success';
    case ERROR = 'error';
}

$type = Schema::enum(MyEnum::class);

$type->toDefinition()->input                // => 'SUCCESS'|'ERROR'
$type->toDefinition()->output               // => 'success'|'error'
$type->asString()->toDefinition()->output   // => 'SUCCESS'|'ERROR'

// Parsing always returns the Enum case itself.
$type->parse(MyEnum::SUCCESS) // => MyEnum::SUCCESS
$type->parse('SUCCESS') // => MyEnum::SUCCESS

// Parsing as strings always returns the string with the enum name.
$type->asString()->parse('SUCCESS') // => 'SUCCESS'
$type->asString()->parse(MyEnum::SUCCESS) // => 'SUCCESS'

// Coercion works with the values
$type->parse('success') // @throws
$type->coerce()->parse('success') // => MyEnum::SUCCESS

未知 / 任何

未知类型和任何类型都以原始形式传递所有数据。

use TypescriptSchema\Schema;

$type = Schema::any();
$type->parse(null) // => null
$type->parse('string') // => 'string'
$type->parse((object) []) // => object{}
$type->parse([]) // => array
// (...)

复杂类型

复杂类型基于原始类型建立,并围绕它们添加功能。以下复杂类型受到支持

  • 对象
  • 数组
  • 记录
  • 元组
  • 联合 / 区分联合

对象

表示具有已知和类型化键值对的JSON中的对象。对象在PHP中通过关联数组定义,其中键必须是字符串,值必须是类型或字段。

use TypescriptSchema\Schema;

$user = Schema::object([
    'name' => Schema::string(),
]);

$user->toDefinition()->input  // => {name: string;}
$user->toDefinition()->output // => {name: string;}

默认情况下,将值解析为字段是通过检查键是否存在于数组或对象的属性中来完成的。

在某些情况下,您可能想要自定义这种解析(例如:您有一个计算输出字段)。

use TypescriptSchema\Schema;
use TypescriptSchema\Definition\Complex\Field;

$user = Schema::object([
    'fullName' => Field::ofType(Schema::string())
        ->resolvedBy(fn(User $user): string => $user->fullName()),
]);

使用字段可以带来更多好处。您可以描述字段甚至使其过时。这对于序列化您的数据的输出类型特别有用。

use TypescriptSchema\Schema;
use TypescriptSchema\Definition\Complex\Field;

$user = Schema::object([
    'fullName' => Field::ofType(Schema::string())
        ->resolvedBy(fn(User $user): string => $user->fullName())
        ->describe('The combination of title, first and last name')
        ->deprecated('Use lastName, firstName and title to compute manually', DateTime::createFromFormat('Y-m-d', '2024-05-25')),
]);