You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让TypeScript根据binanceCoins校验chainName参数合法性?

问题描述

我有一个用于类型校验的对象binanceCoins(可按需修改格式),包含500+条目,示例如下:

export const binanceCoins = {
  AGLD: 'ETH',
  STPT: 'ETH',
  MXN: 'FIAT_MONEY',
  UGX: 'FIAT_MONEY',
  GLM: 'ETH',
  RAY: 'SOL',
  NEAR: 'BSC' || 'NEAR' || 'BNB',
  AUDIO: 'ETH',
  ADADOWN: 'ETF',
  FARM: 'BSC' || 'ETH',
  SDG: 'FIAT_MONEY',
  XNO: 'NANO',
  DGB: 'DGB',
}

同时定义了如下函数:

const topUpFromBinance = async (chainName: string, tokenName: keyof typeof binanceCoins) => {}

目前已实现让tokenName仅能传入binanceCoins的键,现需让TypeScript校验chainName:仅当它是tokenName对应binanceCoins中的有效值时才合法。例如:

  • tokenName为'AGLD'时,chainName只能是'ETH';
  • tokenName为'NEAR'时,chainName可为'BSC' | 'NEAR' | 'BNB';
  • tokenName为'SDG'时,chainName只能是'FIAT_MONEY'。

因对象条目超500条,无法逐个编写接口,请问如何实现该类型校验?是否可行?

解决方案

完全可行,核心是利用TypeScript的泛型和索引类型建立参数间的关联约束,无需手动维护每个条目类型。

步骤1:修正binanceCoins的定义

注意原代码中'BSC' || 'NEAR' || 'BNB'会被JS直接求值为'BSC',无法生成联合类型。需用字面量联合类型配合as const锁定类型:

export const binanceCoins = {
  AGLD: 'ETH',
  STPT: 'ETH',
  MXN: 'FIAT_MONEY',
  UGX: 'FIAT_MONEY',
  GLM: 'ETH',
  RAY: 'SOL',
  NEAR: 'BSC' as const | 'NEAR' | 'BNB',
  AUDIO: 'ETH',
  ADADOWN: 'ETF',
  FARM: 'BSC' as const | 'ETH',
  SDG: 'FIAT_MONEY',
  XNO: 'NANO',
  DGB: 'DGB',
} as const;

as const的作用是让TypeScript保留所有值的字面量类型(而非自动拓宽为string),这样才能提取出精确的合法链名类型。

步骤2:用泛型重构函数

通过泛型参数T绑定tokenName的具体键类型,再通过typeof binanceCoins[T]获取对应链名的合法类型:

const topUpFromBinance = async <T extends keyof typeof binanceCoins>(
  chainName: typeof binanceCoins[T],
  tokenName: T
) => {};

效果验证

调用函数时,TypeScript会自动根据tokenName校验chainName:

  • 传入tokenName: 'AGLD',chainName仅能传'ETH';
  • 传入tokenName: 'NEAR',chainName可传'BSC'/'NEAR'/'BNB'任意一个;
  • 若传入不匹配组合(如tokenName: 'SDG'却传chainName: 'ETH'),TypeScript会直接抛出类型错误。

这种方式完全适配500+条目的对象,所有类型关联由TypeScript自动推导,无需手动编写大量接口。

内容的提问来源于stack exchange,提问作者Eugene1111

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 17:02:36