非泛型函数的泛型工厂:TypeScript替代Parameters类型方案
替代Parameters工具类型实现TypeScript函数参数约束
原始代码示例
const graphql = { query: function<A, B>(x: string, y: (a: A, b: B) => void) { return x; } } function makeOverride<Q, V>(queryName: string) { return (fn: Parameters<typeof graphql.query<Q, V>>[1]) => graphql.query<Q, V>(queryName, fn) } const bound = makeOverride<string, boolean>('some') const bound2 = makeOverride<number, 'cow' | 'dog'>('some') // 正常工作 bound((x: string, y: boolean) => {}) bound2((x: number, y: 'cow' | 'dog') => {})
替代实现方案
以下几种方法都可以在不使用Parameters工具类型的前提下,确保传入makeOverride<A, B>("")(fn)的fn符合(x: A, b: B) => void的约束:
方案1:显式定义回调类型别名
把原函数的回调类型抽成独立别名,让原函数和工厂函数复用这个类型,避免重复定义:
// 提取回调类型为独立别名 type QueryCallback<A, B> = (a: A, b: B) => void; const graphql = { query: function<A, B>(x: string, y: QueryCallback<A, B>) { return x; } } function makeOverride<Q, V>(queryName: string) { return (fn: QueryCallback<Q, V>) => graphql.query<Q, V>(queryName, fn) }
方案2:直接匹配原函数的泛型签名
直接在工厂函数的返回值里,写出和原函数完全一致的回调签名,对应上泛型参数即可:
const graphql = { query: function<A, B>(x: string, y: (a: A, b: B) => void) { return x; } } function makeOverride<Q, V>(queryName: string) { return (fn: (a: Q, b: V) => void) => graphql.query<Q, V>(queryName, fn) }
方案3:提取原函数类型复用
先提取外部库函数的完整类型,再基于该类型复用回调约束,适合类型复杂的外部库场景:
const graphql = { query: function<A, B>(x: string, y: (a: A, b: B) => void) { return x; } } // 提取原函数的类型 type QueryFunction = typeof graphql.query; // 基于原函数类型定义回调类型(无需Parameters) type QueryCallback<A, B> = (a: A, b: B) => void; function makeOverride<Q, V>(queryName: string) { return (fn: QueryCallback<Q, V>) => graphql.query<Q, V>(queryName, fn) }
内容的提问来源于stack exchange,提问作者Pasato
相关产品推荐
相关产品推荐

