Типобезопасный HTTP API на TypeScript без кодогенерации: @cleverbrush/server и @cleverbrush/client
andrew_zol 13 минут назад Типобезопасный HTTP API на TypeScript без кодогенерации: @cleverbrush/server и @cleverbrush/client Уровень сложности Средний Время на прочтение 10 мин Охват и читатели 198 JavaScript *...
Anthropic — What company has the best second artificial intelligence model at the end of June?
В сфере искусственного интеллекта произошло заметное событие. andrew_zol 13 минут назад Типобезопасный HTTP API на TypeScript без кодогенерации: @cleverbrush/server и @cleverbrush/client Уровень сложности Средний Время на прочтение 10 мин Охват и читатели 198 JavaScript * TypeScript * Статья о том, как единый типизированный контракт позволяет получить проверяемые на этапе компиляции сервер, клиент и React-хуки — без кодогенерации и без дублирования типов. Дисклеймер: все описываемые библиотеки носят экспериментальный характер — они созданы в рамках эксперимента. Несмотря на это, покрытие тестами у них достаточно хорошее.
Предыстория В предыдущей статье я рассказывал о @cleverbrush/schema — библиотеке валидации схем с fluent-API и runtime-интроспекцией. Схемы — это краеугольный камень всего фреймворка. Сегодня речь пойдёт о том, что на них строится: типизированный HTTP-сервер @cleverbrush/server и клиент @cleverbrush/client .
Технические детали
Классическая проблема выглядит так: у вас есть бэкенд на TypeScript и фронтенд на TypeScript, но типы между ними не разделены. Либо вы дублируете их в двух местах, либо запускаете кодогенерацию по OpenAPI-манифесту и работаете с «размороженными» типами, которые устаревают сразу после того, как меняется контракт. Здесь работает другой подход: единый контракт API в виде TypeScript-модуля, который импортируется и сервером, и клиентом напрямую.
Контракт как единственный источник правды Контракт — это объект, описывающий все эндпоинты приложения. Он создаётся в отдельном пакете (или файле), не содержит серверного кода и может безопасно импортироваться в браузер. import { array, number, object, string } from '@cleverbrush/schema'; import { defineApi, endpoint, route } from '@cleverbrush/server/contract'; const TodoSchema = object({ id: number(), title: string(), completed: boolean() }); const CreateTodoBodySchema = object({ title: string().
required() }); const ById = route({ id: number(). coerce() })`/${t => t. id}`; export const api = defineApi({ todos: { list: endpoint .
Отраслевые последствия
query(object({ page: number(). responses({ 200: array(TodoSchema) }), get: endpoint . resource('/api/todos') .
responses({ 200: TodoSchema, 404: null }), create: endpoint . body(CreateTodoBodySchema) . responses({ 201: TodoSchema }), delete: endpoint .
resource('/api/todos') . responses({ 204: null }) } }); Заметьте функцию route. Это tagged template, который задаёт путь с типизированными параметрами.
Этот прогресс даёт важные сигналы о будущем отрасли, и технологический мир внимательно наблюдает.





