盡管 Fastify 自帶了 typings 聲明文件,你可能仍然需要根據(jù)所使用的 Node.js 版本來(lái)安裝 @types/node。
我們關(guān)注 TypeScript 社區(qū),當(dāng)前也有一名團(tuán)隊(duì)的核心成員正在重做所有的 types。 我們盡自己最大的努力來(lái)保證 typings 文件與最新的 API 同步,但并不能完全避免不同步的情況發(fā)生。幸運(yùn)的是這是個(gè)開(kāi)源項(xiàng)目,你可以參與修復(fù)。我們十分歡迎你的貢獻(xiàn),并會(huì)盡快發(fā)布補(bǔ)丁。請(qǐng)看 貢獻(xiàn) 指南吧!
插件有可能包含 typings,也可能沒(méi)有。具體信息請(qǐng)參閱 插件類型。
以下 TypeScript 的程序示例和 JavaScript 版本的示例緊密相似:
import * as fastify from 'fastify'
import { Server, IncomingMessage, ServerResponse } from 'http'
// 創(chuàng)建一個(gè) http 服務(wù)器,將 http 對(duì)應(yīng)版本所使用的 typings 傳遞過(guò)去。
// 這么做我們便能獲知路由底層 http 對(duì)象的結(jié)構(gòu)。
// 如果使用 http2,你應(yīng)該傳遞 <http2.Http2Server, http2.Http2ServerRequest, http2.Http2ServerResponse>
// 如果使用 https,則是 http2.Http2SecureServer 或 http.SecureServer,而不是 Server。
const server: fastify.FastifyInstance<Server, IncomingMessage, ServerResponse> = fastify({})
const opts: fastify.RouteShorthandOptions = {
schema: {
response: {
200: {
type: 'object',
properties: {
pong: {
type: 'string'
}
}
}
}
}
}
server.get('/ping', opts, (request, reply) => {
console.log(reply.res) // 帶有正確 typings 的 http.ServerResponse!
reply.code(200).send({ pong: 'it worked!' })
})
你不但可以校驗(yàn) querystring、url 參數(shù)、body 以及 header,你還可以覆蓋 request 接口中定義的默認(rèn)類型:
import * as fastify from 'fastify'
const server = fastify({})
interface Query {
foo?: number
}
interface Params {
bar?: string
}
interface Body {
baz?: string
}
interface Headers {
a?: string
}
const opts: fastify.RouteShorthandOptions = {
schema: {
querystring: {
type: 'object',
properties: {
foo: {
type: 'number'
}
}
},
params: {
type: 'object',
properties: {
bar: {
type: 'string'
}
}
},
body: {
type: 'object',
properties: {
baz: {
type: 'string'
}
}
},
headers: {
type: 'object',
properties: {
a: {
type: 'string'
}
}
}
}
}
server.get<Query, Params, Headers, Body>('/ping/:bar', opts, (request, reply) => {
console.log(request.query) // 這是 Query 類型
console.log(request.params) // 這是 Params 類型
console.log(request.body) // 這是 Body 類型
console.log(request.headers) // 這是 Headers 類型
reply.code(200).send({ pong: 'it worked!' })
})
所有的一般類型都是可選的,因此你可以只傳遞你使用 schema 校驗(yàn)的類型:
import * as fastify from 'fastify'
const server = fastify({})
interface Params {
bar?: string
}
const opts: fastify.RouteShorthandOptions = {
schema: {
params: {
type: 'object',
properties: {
bar: {
type: 'string'
}
}
},
}
}
server.get<fastify.DefaultQuery, Params, unknown>('/ping/:bar', opts, (request, reply) => {
console.log(request.query) // 這是 fastify.DefaultQuery 類型
console.log(request.params) // 這是 Params 類型
console.log(request.body) // 這是未知的類型
console.log(request.headers) // 這是 fastify.DefaultHeader 類型,因?yàn)?typescript 會(huì)使用默認(rèn)類型
reply.code(200).send({ pong: 'it worked!' })
})
// 假設(shè)你不校驗(yàn) querystring、body 或者 header,
// 最好將類型設(shè)為 `unknown`。但這個(gè)選擇取決于你。
// 下面的例子展示了這一做法,它可以避免你搬起石頭砸自己的腳。
// 換句話說(shuō),就是別使用不去校驗(yàn)的類型。
server.get<unknown, Params, unknown, unknown>('/ping/:bar', opts, (request, reply) => {
console.log(request.query) // 這是未知的類型
console.log(request.params) // 這是 Params 類型
console.log(request.body) // 這是未知的類型
console.log(request.headers) // 這是未知的類型
reply.code(200).send({ pong: 'it worked!' })
})
默認(rèn)情況下,F(xiàn)astify 會(huì)根據(jù)你給的配置決定使用 http 的哪個(gè)版本。出于某種原因需要覆蓋的話,你可以這么做:
interface CustomIncomingMessage extends http.IncomingMessage {
getClientDeviceType: () => string
}
// 將覆蓋的 http 原型傳給 Fastify
const server: fastify.FastifyInstance<http.Server, CustomIncomingMessage, http.ServerResponse> = fastify()
server.get('/ping', (request, reply) => {
// 使用自定義的 http 原型方法
const clientDeviceType = request.raw.getClientDeviceType()
reply.send({ clientDeviceType: `you called this endpoint from a ${clientDeviceType}` })
})
在這個(gè)例子中,我們傳遞了一個(gè)經(jīng)過(guò)修改的 http.IncomingMessage 接口,該接口在程序的其他地方得到了擴(kuò)展。
和 TypeScript 相關(guān)的改動(dòng)可以被歸入下列類別:
記得要先閱讀 CONTRIBUTING.md 文件,確保行事順利!
當(dāng)更新核心類型時(shí),你應(yīng)當(dāng)向本倉(cāng)庫(kù)發(fā)一個(gè) PR。請(qǐng)確保:
和 fastify 倉(cāng)庫(kù)一樣,由 GitHub 上的 fastify 組織所維護(hù)的插件,應(yīng)當(dāng)自帶 typings 文件。 目前一些插件還沒(méi)有 typings 文件,我們很歡迎你參與其中。typings 的例子請(qǐng)看 fastify-cors 倉(cāng)庫(kù)。
第三方插件可能自帶 typings 文件,或存放于 DefinitelyTyped 之上。請(qǐng)記住,如果你寫了一個(gè)插件,也請(qǐng)選擇上述兩種途徑之一來(lái)存放 typings 文件!從 DefinitelyTyped 安裝 typings 的方法可以在這里找到。
一些類型可能還不可用,因此盡管去貢獻(xiàn)吧。
擴(kuò)展了 FastifyRequest、FastifyReply 或 FastifyInstance 對(duì)象的許多插件,可以通過(guò)如下方式獲取。
以下代碼展示了 fastify-static 插件的 typings。
/// <reference types="node" />
// 導(dǎo)入 fastify typings
import * as fastify from 'fastify';
// 導(dǎo)入必需的 http, http2, https typings
import { Server, IncomingMessage, ServerResponse } from "http";
import { Http2SecureServer, Http2Server, Http2ServerRequest, Http2ServerResponse } from "http2";
import * as https from "https";
type HttpServer = Server | Http2Server | Http2SecureServer | https.Server;
type HttpRequest = IncomingMessage | Http2ServerRequest;
type HttpResponse = ServerResponse | Http2ServerResponse;
// 拓展 fastify typings
declare module "fastify" {
interface FastifyReply<HttpResponse> {
sendFile(filename: string): FastifyReply<HttpResponse>;
}
}
// 使用 fastify.Plugin 聲明插件的類型
declare function fastifyStatic(): fastify.Plugin<
Server,
IncomingMessage,
ServerResponse,
{
root: string;
prefix?: string;
serve?: boolean;
decorateReply?: boolean;
schemaHide?: boolean;
setHeaders?: (...args: any[]) => void;
redirect?: boolean;
wildcard?: boolean | string;
// `send` 的選項(xiàng)
acceptRanges?: boolean;
cacheControl?: boolean;
dotfiles?: boolean;
etag?: boolean;
extensions?: string[];
immutable?: boolean;
index?: string[];
lastModified?: boolean;
maxAge?: string | number;
}
>;
declare namespace fastifyStatic {
interface FastifyStaticOptions {}
}
// 導(dǎo)出插件類型
export = fastifyStatic;
現(xiàn)在你便可以如此使用插件了:
import * as Fastify from 'fastify'
import * as fastifyStatic from 'fastify-static'
const app = Fastify()
// 這里的配置項(xiàng)會(huì)類型檢查
app.register(fastifyStatic, {
acceptRanges: true,
cacheControl: true,
decorateReply: true,
dotfiles: true,
etag: true,
extensions: ['.js'],
immutable: true,
index: ['1'],
lastModified: true,
maxAge: '',
prefix: '',
root: '',
schemaHide: true,
serve: true,
setHeaders: (res, pathName) => {
res.setHeader('some-header', pathName)
}
})
app.get('/file', (request, reply) => {
// 使用上文定義的 FastifyReply.sendFile 方法
reply.sendFile('some-file-name')
})
給我們所有的插件加上 typings 需要社區(qū)的努力,因此盡管來(lái)貢獻(xiàn)吧!
更多建議: