TypeScript泛型函数:参数类型推断与可选参数默认值报错问题
问题
我想要编写一个泛型函数doThing<T, U extends T>(opts): U,其中类型U能从传入的opts参数中自动推断;核心要求是:如果未传入responseTransformer选项则使用默认值,此时T与U类型保持一致。
示例代码如下:
type Opts<Response, TransformedResponse extends Response> = { fetch: () => Response; responseTransformer?: (response: Response) => TransformedResponse; }; function defaultResponseTransformer<Response> (response: Response): Response { return response; } function doApiFetch<Response, TransformedResponse extends Response>({ fetch, responseTransformer = defaultResponseTransformer, // 理想情况:未指定responseTransformer时TransformedResponse推断为Response }: Opts<Response, TransformedResponse>): TransformedResponse { return responseTransformer(fetch()); }
将defaultResponseTransformer作为默认值写在解构语句中时,出现错误提示:'TransformedResponse' could be instantiated with an arbitrary type which could be unrelated to 'Response'.
解决方案
方法1:使用函数重载
通过定义函数重载,明确区分「未提供转换器」和「提供转换器」两种调用场景,让TypeScript能精准推断类型:
type Opts<Response, TransformedResponse extends Response> = { fetch: () => Response; responseTransformer?: (response: Response) => TransformedResponse; }; function defaultResponseTransformer<Response>(response: Response): Response { return response; } // 重载1:未传入responseTransformer时,返回类型与fetch的返回类型一致 function doApiFetch<Response>(opts: Omit<Opts<Response, Response>, 'responseTransformer'>): Response; // 重载2:传入responseTransformer时,返回转换后的目标类型 function doApiFetch<Response, TransformedResponse extends Response>(opts: Opts<Response, TransformedResponse>): TransformedResponse; // 函数实现 function doApiFetch<Response, TransformedResponse extends Response>({ fetch, responseTransformer = defaultResponseTransformer, }: Opts<Response, TransformedResponse>): TransformedResponse | Response { return responseTransformer(fetch()); }
方法2:调整泛型约束与默认值
给TransformedResponse设置默认类型为Response,同时通过类型断言让默认值的类型与泛型匹配,解决类型不兼容问题:
type Opts<Response, TransformedResponse extends Response = Response> = { fetch: () => Response; responseTransformer?: ((response: Response) => TransformedResponse) | undefined; }; function defaultResponseTransformer<Response>(response: Response): Response { return response; } function doApiFetch<Response, TransformedResponse extends Response = Response>({ fetch, responseTransformer = defaultResponseTransformer as (response: Response) => TransformedResponse, }: Opts<Response, TransformedResponse>): TransformedResponse { return responseTransformer(fetch()); }
错误原因说明
原代码报错是因为:当未传入responseTransformer时,TypeScript无法确定TransformedResponse的具体类型——它可能被推断为任意继承自Response的类型,但默认值defaultResponseTransformer的类型是(response: Response) => Response,和不确定的TransformedResponse无法兼容,因此抛出类型不匹配的错误。
内容的提问来源于stack exchange,提问作者Trevor Dixon
相关产品推荐
相关产品推荐

