类型提供器
类型提供器是 TypeScript 的一个特性,它使 Fastify 能够从内联 JSON Schema 中推断出类型信息。它们可以作为在路由中指定泛型参数的替代方案,并且减少了项目中为每个模式保持关联类型的需要。
提供器
官方类型提供器包遵循 @fastify/type-provider-{provider-name}
的命名约定。
社区提供的多个插件也已可用。
以下推断包受支持:
请参阅每个包的类型提供器包装器包:
@fastify/type-provider-json-schema-to-ts
@fastify/type-provider-typebox
fastify-type-provider-zod
(第三方)
Json Schema to Ts
以下代码设置了一个 json-schema-to-ts
类型提供器:
$ npm i @fastify/type-provider-json-schema-to-ts
import fastify from 'fastify'
import { JsonSchemaToTsProvider } from '@fastify/type-provider-json-schema-to-ts'
const server = fastify().withTypeProvider<JsonSchemaToTsProvider>()
server.get('/route', {
schema: {
querystring: {
type: 'object',
properties: {
foo: { type: 'number' },
bar: { type: 'string' },
},
required: ['foo', 'bar']
}
}
}, (request, reply) => {
// 类型 Query = { foo: number, bar: string }
const { foo, bar } = request.query // 安全类型!
})
TypeBox
以下代码设置了一个TypeBox类型提供器:
$ npm i @fastify/type-provider-typebox
import fastify from 'fastify'
import { TypeBoxTypeProvider } from '@fastify/type-provider-typebox'
import { Type } from '@sinclair/typebox'
const server = fastify().withTypeProvider<TypeBoxTypeProvider>()
server.get('/route', {
schema: {
querystring: Type.Object({
foo: Type.Number(),
bar: Type.String()
})
}
}, (request, reply) => {
// type Query = { foo: number, bar: string }
const { foo, bar } = request.query // 类型安全!
})
有关如何使用TypeBox设置AJV的文档,请参阅 TypeBox 文档 。
Zod
有关Zod类型提供器的说明,请参阅 官方文档 。
命名空间类型提供器
提供器类型不会全局传播。在封装使用中,可以重新映射上下文以使用一个或多个提供器(例如,可以在同一应用程序中同时使用 typebox
和 json-schema-to-ts
)。
示例:
import Fastify from 'fastify'
import { TypeBoxTypeProvider } from '@fastify/type-provider-typebox'
import { JsonSchemaToTsProvider } from '@fastify/type-provider-json-schema-to-ts'
import { Type } from '@sinclair/typebox'
const fastify = Fastify()
function pluginWithTypebox(fastify: FastifyInstance, _opts, done): void {
fastify.withTypeProvider<TypeBoxTypeProvider>()
.get('/', {
schema: {
body: Type.Object({
x: Type.String(),
y: Type.Number(),
z: Type.Boolean()
})
}
}, (req) => {
const { x, y, z } = req.body // 类型安全
});
done()
}
function pluginWithJsonSchema(fastify: FastifyInstance, _opts, done): void {
fastify.withTypeProvider<JsonSchemaToTsProvider>()
.get('/', {
schema: {
body: {
type: 'object',
properties: {
x: { type: 'string' },
y: { type: 'number' },
z: { type: 'boolean' }
},
}
}
}, (req) => {
const { x, y, z } = req.body // 类型安全
});
done()
}
fastify.register(pluginWithJsonSchema)
fastify.register(pluginWithTypebox)
请注意,由于类型不会全局传播,在处理多个作用域时,目前无法避免在路由上进行多次注册,如下所示:
import Fastify from 'fastify'
import { TypeBoxTypeProvider } from '@fastify/type-provider-typebox'
import { Type } from '@sinclair/typebox'
const server = Fastify().withTypeProvider<TypeBoxTypeProvider>()
server.register(plugin1) // 错误
server.register(plugin2) // 正确
function plugin1(fastify: FastifyInstance, _opts, done): void {
fastify.get('/', {
schema: {
body: Type.Object({
x: Type.String(),
y: Type.Number(),
z: Type.Boolean()
})
}
}, (req) => {
// 在新的作用域中,再次调用 `withTypeProvider` 确保其正常工作
const { x, y, z } = req.body
});
done()
}
function plugin2(fastify: FastifyInstance, _opts, done): void {
const server = fastify.withTypeProvider<TypeBoxTypeProvider>()
server.get('/', {
schema: {
body: Type.Object({
x: Type.String(),
y: Type.Number(),
z: Type.Boolean()
})
}
}, (req) => {
// 正常工作
const { x, y, z } = req.body
});
done()
}
FastifyInstance 类型定义及 TypeProvider
在使用模块时,请结合 FastifyInstance
和 Type Provider 泛型。
请参阅下面的示例:
// index.ts
import Fastify from 'fastify'
import { TypeBoxTypeProvider } from '@fastify/type-provider-typebox'
import { registerRoutes } from './routes'
const server = Fastify().withTypeProvider<TypeBoxTypeProvider>()
registerRoutes(server)
server.listen({ port: 3000 })
// routes.ts
import { Type } from '@sinclair/typebox'
import {
FastifyInstance,
FastifyBaseLogger,
RawReplyDefaultExpression,
RawRequestDefaultExpression,
RawServerDefault
} from 'fastify'
import { TypeBoxTypeProvider } from '@fastify/type-provider-typebox'
type FastifyTypebox = FastifyInstance<
RawServerDefault,
RawRequestDefaultExpression<RawServerDefault>,
RawReplyDefaultExpression<RawServerDefault>,
FastifyBaseLogger,
TypeBoxTypeProvider
>;
export function registerRoutes(fastify: FastifyTypebox): void {
fastify.get('/', {
schema: {
body: Type.Object({
x: Type.String(),
y: Type.Number(),
z: Type.Boolean()
})
}
}, (req) => {
// 可用
const { x, y, z } = req.body
});
}