如何基于已有泛型构建新泛型?TypeScript方案探讨
TypeScript中基于已有泛型构建新泛型的优化方案
本文探讨在TypeScript中如何分阶段复用泛型:先固定某一个泛型参数,后续再传入另一个参数构建最终类型。以下是需求的伪代码示例(仅用于表达逻辑,非合法TS语法):
type Foo<A> = { Bar<B>: { a: A, b: B } } // 第一步:固定A为string type FooString = Foo<string> // 期望得到 { Bar<B>: { a: string, b: B } } // 后续使用:传入B得到最终类型 type FooBarNumber = FooString['Bar']<number> // 期望得到 { a: string, b: number } type FooBarBoolean = FooString['Bar']<boolean> // 期望得到 { a: string, b: boolean }
现有两种临时方案均存在缺陷:
一次性双参数泛型:违反DRY原则,每次使用都需重复书写固定的A类型:
type FooBar1<A, B> = { a: A, b: B } type FooBarNumber1 = FooBar1<string, number> type FooBarBoolean1 = FooBar1<string, boolean>类型合并方案:依赖类型可合并的前提,无法适配所有场景:
type Foo2<A, R = { a: A }> = R type FooString2 = Foo2<string> type Bar2<F extends { a: unknown }, B, R = F & { b: B }> = R type FooBarNumber2 = Bar2<FooString2, number> type FooBarBoolean2 = Bar2<FooString2, boolean>
优化解决方案
方案1:泛型函数类型作为属性
将Bar定义为泛型函数类型(返回目标类型),通过ReturnType提取最终类型:
type Foo<A> = { Bar: <B>() => { a: A, b: B } } type FooString = Foo<string> // 提取Bar<B>的返回类型 type FooBarNumber = ReturnType<FooString['Bar']<number>> type FooBarBoolean = ReturnType<FooString['Bar']<boolean>>
方案2:柯里化高阶泛型
定义柯里化的泛型类型,先固定A,再传入B:
type CurriedFoo<A> = <B>() => { a: A, b: B } // 固定A为string type FooString = CurriedFoo<string> // 传入B得到最终类型 type FooBarNumber = ReturnType<FooString<number>> type FooBarBoolean = ReturnType<FooString<boolean>>
方案3:基础类型+工具封装
基于基础类型封装分阶段泛型,兼顾可读性与复用性:
// 基础目标类型 type FooBarBase<A, B> = { a: A, b: B } // 固定A后返回接受B的泛型函数类型 type Foo<A> = { Bar: <B>() => FooBarBase<A, B> } type FooString = Foo<string> type FooBarNumber = ReturnType<FooString['Bar']<number>> type FooBarBoolean = ReturnType<FooString['Bar']<boolean>>
这些方案均实现了分阶段泛型复用,避免重复书写固定参数,符合DRY原则,且无需依赖类型合并的限制。
内容的提问来源于stack exchange,提问作者TrevTheDev
相关产品推荐
相关产品推荐

