类型提供者
类型提供者
¥Type Providers
类型提供程序是仅 TypeScript 的功能,使 Fastify 能够直接从内联 JSON 模式静态推断类型信息。它们是在路由上指定通用参数的替代方法;并且可以大大减少为项目中定义的每个模式保留关联类型的需要。
¥Type Providers are a TypeScript only feature that enables Fastify to statically infer type information directly from inline JSON Schema. They are an alternative to specifying generic arguments on routes; and can greatly reduce the need to keep associated types for each schema defined in your project.
提供者
¥Providers
类型提供程序作为附加包提供,你需要将其安装到项目中。每个提供商在底层都使用不同的推断库;允许你选择最适合你需求的库。官方类型提供程序包遵循 @fastify/type-provider-{provider-name}
命名约定,并且还有几个社区包可用。
¥Type Providers are offered as additional packages you will need to install into
your project. Each provider uses a different inference library under the hood;
allowing you to select the library most appropriate for your needs. Official Type
Provider packages follow a @fastify/type-provider-{provider-name}
naming
convention, and there are several community ones available as well.
支持以下推断包:
¥The following inference packages are supported:
另请参阅每个包的类型提供程序封装器包:
¥See also the Type Provider wrapper packages for each of the packages respectively:
fastify-type-provider-zod
(第三方)¥
fastify-type-provider-zod
(3rd party)
Json 模式到 Ts
¥Json Schema to Ts
以下设置了一个 json-schema-to-ts
类型提供程序
¥The following sets up a json-schema-to-ts
Type Provider
$ 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) => {
// type Query = { foo: number, bar: string }
const { foo, bar } = request.query // type safe!
})
TypeBox
下面设置一个 TypeBox Type Provider
¥The following sets up a TypeBox Type Provider
$ 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 // type safe!
})
另请参阅 类型框文档 以了解如何设置 AJV 以与 TypeBox 配合使用。
¥See also the TypeBox documentation on how to set up AJV to work with TypeBox.
Zod
请参阅 官方文档 了解 Zod 类型提供程序说明。
¥See official documentation for Zod type provider instructions.
作用域类型提供者
¥Scoped Type-Provider
提供者类型不会在全局范围内传播。在封装使用中,可以重新映射上下文以使用一个或多个提供程序(例如,typebox
和 json-schema-to-ts
可以在同一应用中使用)。
¥The provider types don't propagate globally. In encapsulated usage, one can
remap the context to use one or more providers (for example, typebox
and
json-schema-to-ts
can be used in the same application).
示例:
¥Example:
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 // type safe
});
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 // type safe
});
done()
}
fastify.register(pluginWithJsonSchema)
fastify.register(pluginWithTypebox)
还需要提到的是,由于类型不会全局传播,因此目前无法避免在处理多个范围时在路由上进行多次注册,如下所示:
¥It's also important to mention that since the types don't propagate globally, currently it is not possible to avoid multiple registrations on routes when dealing with several scopes, see below:
import Fastify from 'fastify'
import { TypeBoxTypeProvider } from '@fastify/type-provider-typebox'
import { Type } from '@sinclair/typebox'
const server = Fastify().withTypeProvider<TypeBoxTypeProvider>()
server.register(plugin1) // wrong
server.register(plugin2) // correct
function plugin1(fastify: FastifyInstance, _opts, done): void {
fastify.get('/', {
schema: {
body: Type.Object({
x: Type.String(),
y: Type.Number(),
z: Type.Boolean()
})
}
}, (req) => {
// it doesn't work! in a new scope needs to call `withTypeProvider` again
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) => {
// works
const { x, y, z } = req.body
});
done()
}
FastifyInstance + TypeProvider 的类型定义
¥Type Definition of FastifyInstance + TypeProvider
使用模块时,必须使用带有类型提供程序泛型的 FastifyInstance
。请参阅下面的示例:
¥When working with modules one has to make use of FastifyInstance
with Type
Provider generics. See the example below:
// 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) => {
// works
const { x, y, z } = req.body
});
}