用TypeScript扩展Express Response.render()类型定义



我正试图在我的Express项目中获得一些更智能的打字,但我在扩展Response.render功能时遇到了麻烦。

import { Response } from "express";
import { Product } from "../models/Product.interface";
export interface ProductListResponse extends Response {
render: (view: string, options?: { products: Product[] }) => void;
}

原点定义如下:

render(view: string, options?: object, callback?: (err: Error, html: string) => void): void;
render(view: string, callback?: (err: Error, html: string) => void): void;

当我试图编译这个时,我得到

src/routes/product.interface.ts:13:18 - error TS2430: Interface 'ProductListResponse' incorrectly extends interface 'Response<any, Record<string, any>>'.
Types of property 'render' are incompatible.
Type '(view: string, options: { products: Product[]; }) => void' is not assignable to type '{ (view: string, options?: object, callback?: (err: Error, html: string) => void): void; (view: string, callback?: (err: Error, html: string) => void): void; }'.
Types of parameters 'options' and 'callback' are incompatible.
Property 'products' is missing in type '(err: Error, html: string) => void' but required in type '{ products: Product[]; }'.
13 export interface ProductListResponse extends Response {
~~~~~~~~~~~~~~~~~~~
src/routes/product.interface.ts:14:37
14     render(view: string, options: { products: Product[] }): void;
~~~~~~~~
'products' is declared here.

Found 2 errors.

我认为我可以通过扩展基本接口来覆盖render的定义,但显然这不是真的。任何帮助都将非常感激。谢谢!

您可以在express的Response类型中省略render定义。然后,重新定义渲染函数:

interface ProductListResponse extends Omit<Response, 'render'> {
render: (view: string, options?: { products: Product[] }) => void;
}

您需要将Response接口的.render()方法重载签名添加到您的自定义ProductListResponse接口中。

import express, { Response } from 'express';
interface Product {}
export interface ProductListResponse extends Response {
render(view: string, options?: { products: Product[] }): void;
render(view: string, options?: object, callback?: (err: Error, html: string) => void): void;
render(view: string, callback?: (err: Error, html: string) => void): void;
}
const app = express();
app.get('/', (req, res: ProductListResponse) => {
res.render('index', { products: [] });
});

或者,使用交集类型

import express, { Response } from 'express';
interface Product {}
export interface ProductListResponse {
render(view: string, options?: { products: Product[] }): void;
}
const app = express();
app.get('/', (req, res: ProductListResponse & Response) => {
res.render('index', { products: [] });
});

TypeScript version:4.4.4