Node 10中Express与TypeScript结合http2的类型兼容问题咨询
你遇到的问题其实很典型——Express的官方类型定义(@types/express)确实是基于Node.js的http模块设计的,而http2.createServer期望的处理函数参数类型是Http2ServerRequest/Http2ServerResponse,和Express的Request/Response类型天然不兼容,而且目前确实没有官方的@types/express-http2包,因为Express本身是通过兼容http接口的方式支持http2的,类型层面没做针对性适配。
下面给你几个可行的解决方案,按优先级排序:
1. 优化类型断言,避免频繁any转换
你可以自定义交叉类型,把Express的请求响应类型和http2的类型合并,同时给app做一次安全的类型转换,不用每次路由处理都重复写冗长的断言:
import * as express from 'express'; import * as http2 from 'http2'; // 定义合并后的类型,同时保留Express和http2的所有属性方法 type Http2ExpressRequest = express.Request & http2.Http2ServerRequest; type Http2ExpressResponse = express.Response & http2.Http2ServerResponse; // 一次性转换app的类型,替代多次`as any`的写法 const http2CompatibleApp = app as express.Express & ((req: http2.Http2ServerRequest, res: http2.Http2ServerResponse) => void); // 创建http2服务器 const server = http2.createServer({}, http2CompatibleApp).listen(8080); // 路由中直接使用合并后的类型 app.get('/', (req: Http2ExpressRequest, res: Http2ExpressResponse) => { // 直接调用http2的push方法,无需额外转换 res.push('/static/style.css', { status: 200, headers: { 'content-type': 'text/css' } }).end('body { margin: 0; padding: 1rem; }'); res.send('Hello HTTP/2 with Express!'); });
这种方式比用any更安全,能保留完整的类型提示和编译检查,同时大幅减少重复代码。
2. 扩展Express的全局类型定义
你可以在项目中创建自定义的类型扩展文件,让Express的Request/Response自动包含http2的类型,彻底告别手动断言:
- 在项目根目录创建
typings/express/index.d.ts文件,内容如下:
import * as http2 from 'http2'; declare module 'express' { // 让Express的Request继承Http2ServerRequest的所有属性 interface Request extends http2.Http2ServerRequest {} // 让Express的Response继承Http2ServerResponse的所有属性 interface Response extends http2.Http2ServerResponse {} }
- 修改
tsconfig.json,确保这个目录被包含在类型扫描范围内:
{ "compilerOptions": { // 其他配置... "typeRoots": ["./node_modules/@types", "./typings"] }, "include": ["./src/**/*", "./typings/**/*"] }
之后你在代码中直接使用Express的请求响应对象,就能直接调用http2的方法(比如res.push()),不需要任何类型转换。
3. 更换为原生支持http2的Web框架
如果可以接受更换框架,推荐使用Fastify——它原生支持http2,且有完善的TypeScript类型定义,对http2的支持是一等公民,不需要处理类型兼容问题,同时性能比Express更出色。
示例代码:
import fastify from 'fastify'; import fs from 'fs'; // 初始化支持http2的Fastify实例(注意http2需要HTTPS环境) const app = fastify({ http2: true, https: { key: fs.readFileSync('./server.key'), cert: fs.readFileSync('./server.cert') } }); // 路由中直接使用http2功能 app.get('/', async (request, reply) => { // 直接调用push方法 reply.push('/static/style.css', { status: 200, headers: { 'content-type': 'text/css' } }).end('body { background: #f5f5f5; }'); return { message: 'Hello HTTP/2 with Fastify!' }; }); app.listen({ port: 8080 }, (err) => { if (err) { console.error(err); process.exit(1); } console.log('HTTP/2 server running on https://localhost:8080'); });
另外,Koa也可以结合http2使用,且有官方TypeScript类型支持,但Koa的中间件风格和Express差异较大,需要一定的学习成本。
内容的提问来源于stack exchange,提问作者Michael Tiller

