TypeScript與類型支持

2020-02-06 15:44 更新

TypeScript

盡管 Fastify 自帶了 typings 聲明文件,你可能仍然需要根據所使用的 Node.js 版本來安裝 @types/node。

Types 支持

我們關注 TypeScript 社區(qū),當前也有一名團隊的核心成員正在重做所有的 types。 我們盡自己最大的努力來保證 typings 文件與最新的 API 同步,但并不能完全避免不同步的情況發(fā)生。幸運的是這是個開源項目,你可以參與修復。我們十分歡迎你的貢獻,并會盡快發(fā)布補丁。請看 貢獻 指南吧!

插件有可能包含 typings,也可能沒有。具體信息請參閱 插件類型。

示例

以下 TypeScript 的程序示例和 JavaScript 版本的示例緊密相似:

import * as fastify from 'fastify'
import { Server, IncomingMessage, ServerResponse } from 'http'

// 創(chuàng)建一個 http 服務器,將 http 對應版本所使用的 typings 傳遞過去。
// 這么做我們便能獲知路由底層 http 對象的結構。
// 如果使用 http2,你應該傳遞 <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!' })
})

一般類型的參數

你不但可以校驗 querystring、url 參數、body 以及 header,你還可以覆蓋 request 接口中定義的默認類型:

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 校驗的類型:

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 類型,因為 typescript 會使用默認類型
  reply.code(200).send({ pong: 'it worked!' })
})

// 假設你不校驗 querystring、body 或者 header,
// 最好將類型設為 `unknown`。但這個選擇取決于你。
// 下面的例子展示了這一做法,它可以避免你搬起石頭砸自己的腳。
// 換句話說,就是別使用不去校驗的類型。
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!' })
})

HTTP 原型

默認情況下,Fastify 會根據你給的配置決定使用 http 的哪個版本。出于某種原因需要覆蓋的話,你可以這么做:

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}` })
})

在這個例子中,我們傳遞了一個經過修改的 http.IncomingMessage 接口,該接口在程序的其他地方得到了擴展。

貢獻

和 TypeScript 相關的改動可以被歸入下列類別:

  • Core - Fastify 的 typings 文件
  • Plugins - Fastify 插件

記得要先閱讀 CONTRIBUTING.md 文件,確保行事順利!

核心類型

當更新核心類型時,你應當向本倉庫發(fā)一個 PR。請確保:

  1. 將改動反映在 examples/typescript-server.ts 文件中 (當需要時)
  2. 更新 test/types/index.ts 來驗證改動是否成功

插件類型

和 fastify 倉庫一樣,由 GitHub 上的 fastify 組織所維護的插件,應當自帶 typings 文件。 目前一些插件還沒有 typings 文件,我們很歡迎你參與其中。typings 的例子請看 fastify-cors 倉庫。

第三方插件可能自帶 typings 文件,或存放于 DefinitelyTyped 之上。請記住,如果你寫了一個插件,也請選擇上述兩種途徑之一來存放 typings 文件!從 DefinitelyTyped 安裝 typings 的方法可以在這里找到。

一些類型可能還不可用,因此盡管去貢獻吧。

編寫插件類型

擴展了 FastifyRequest、FastifyReply 或 FastifyInstance 對象的許多插件,可以通過如下方式獲取。

以下代碼展示了 fastify-static 插件的 typings。

/// <reference types="node" />

// 導入 fastify typings
import * as fastify from 'fastify';

// 導入必需的 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` 的選項
    acceptRanges?: boolean;
    cacheControl?: boolean;
    dotfiles?: boolean;
    etag?: boolean;
    extensions?: string[];
    immutable?: boolean;
    index?: string[];
    lastModified?: boolean;
    maxAge?: string | number;
  }
>;

declare namespace fastifyStatic {
  interface FastifyStaticOptions {}
}

// 導出插件類型
export = fastifyStatic;

現在你便可以如此使用插件了:

import * as Fastify from 'fastify'
import * as fastifyStatic from 'fastify-static'

const app = Fastify()

// 這里的配置項會類型檢查
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ū)的努力,因此盡管來貢獻吧!


以上內容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號