TypeScript如何限制泛型仅接受成员数大于1的联合类型?
实现泛型工具类型
MoreThanOne<T, R> 要实现你需要的泛型工具类型,我们可以利用TypeScript的联合类型分发特性来判断一个类型是否为联合类型,进而返回对应的结果。以下是完整的解决方案:
步骤1:实现IsUnion类型判断工具
首先我们需要一个辅助类型来检测输入类型是否为联合类型:
type IsUnion<T, U = T> = T extends U ? [U] extends [T] ? false : true : never;
原理说明:
- 当
T是联合类型时(比如Currency.EUR | Currency.USD),T extends U会触发TypeScript的分发特性,将联合类型拆分为单个成员分别判断。此时U是原始的联合类型,[U] extends [T]会判断原始联合类型是否能赋值给单个成员的数组类型——显然不能,因此返回true。 - 当
T是单个类型时(比如Currency.EUR),[U] extends [T]等价于[Currency.EUR] extends [Currency.EUR],返回true,因此外层条件返回false。
步骤2:实现MoreThanOne工具类型
基于IsUnion,我们可以写出目标工具类型:
type MoreThanOne<T extends R, R> = IsUnion<T> extends true ? T : never;
逻辑说明:
- 如果
T是联合类型,直接返回T本身,允许函数接收该类型的参数; - 如果
T不是联合类型(即单个成员),返回never,此时函数参数要求never类型,会触发编译错误。
完整示例验证
将你的代码和工具类型结合,验证效果:
enum Currency { EUR = "eur", USD = "usd", PLN = "pln", RUB = "rub" } type Token<T extends Currency = Currency> = { type: T; value: string; }; const token1: Token<Currency.EUR> = { type: Currency.EUR, value: "1" } const token2: Token<Currency.USD> = { type: Currency.USD, value: "1" } const currencies = [token1, token2]; const currencyNonUnion = token1.type; // 类型:Currency.EUR const currencyUnion = currencies[0].type; // 类型:Currency.EUR | Currency.USD // 辅助类型 type IsUnion<T, U = T> = T extends U ? [U] extends [T] ? false : true : never; // 目标工具类型 type MoreThanOne<T extends R, R> = IsUnion<T> extends true ? T : never; // 测试函数 const foo = <T extends Currency>(curr: MoreThanOne<T, Currency>) => { /* 函数逻辑 */ } foo(currencyUnion); // ✅ 编译通过,符合预期 foo(currencyNonUnion); // ❌ 编译错误:类型 "Currency.EUR" 不能赋值给类型 "never"
这样就完美实现了你需要的效果:仅允许传入联合类型的参数,单个类型参数会触发编译错误。
内容的提问来源于stack exchange,提问作者Paweł Lula
相关产品推荐
相关产品推荐

