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

如何让TypeScript的test函数在非数量型Item时无需传requirements参数

TypeScript 可选属性优化问题

问题背景

定义了如下类型和函数:

type Item = 'itemA' | 'itemB' | 'itemC' | 'itemD';
type QuantityBasedItem = 'itemA' | 'itemC'; // 数量型项示例定义
type BooleanBasedItem = Exclude<Item, QuantityBasedItem>;

type MyType<T extends Item> = {
  name: T;
  requirements: T extends QuantityBasedItem ? { units: number } : undefined;
};

const getQuantityBasedItemData = (item: QuantityBasedItem, units: number) => ({item, units});
const getBooleanBasedItemData = (item: BooleanBasedItem) => item;

function test<T extends Item>(itemData: MyType<T>) {
  if(itemData.requirements?.units){
     getQuantityBasedItemData(itemData.name, itemData.requirements)
  } else {
     getBooleanBasedItemData(itemData.name)
  }
}

当前调用test时,非数量型项必须显式传入requirements: undefined才能通过类型检查:

test({name: 'itemB', requirements: undefined}); // 正常运行
test({name: 'itemB'}); // 类型报错

需要修改代码,让非数量型项调用test时无需传入requirements参数。

解决方案

方法一:拆分联合类型

直接将MyType拆分为数量型和布尔型两种场景的联合类型,明确区分必填和可选属性:

type Item = 'itemA' | 'itemB' | 'itemC' | 'itemD';
type QuantityBasedItem = 'itemA' | 'itemC';
type BooleanBasedItem = Exclude<Item, QuantityBasedItem>;

// 联合类型分别定义两种项的结构
type MyType = 
  | { name: QuantityBasedItem; requirements: { units: number } }
  | { name: BooleanBasedItem; requirements?: undefined };

const getQuantityBasedItemData = (item: QuantityBasedItem, units: number) => ({item, units});
const getBooleanBasedItemData = (item: BooleanBasedItem) => item;

function test(itemData: MyType) {
  if (itemData.requirements && 'units' in itemData.requirements) {
     getQuantityBasedItemData(itemData.name, itemData.requirements)
  } else {
     getBooleanBasedItemData(itemData.name)
  }
}

// 测试用例
test({name: 'itemA', requirements: {units: 5}}); // 正常
test({name: 'itemB'}); // 无需传requirements,正常
test({name: 'itemC', requirements: {units: 10}}); // 正常
test({name: 'itemD'}); // 正常

方法二:条件类型结合可选属性

通过交叉类型,让布尔型项的requirements成为可选属性:

type Item = 'itemA' | 'itemB' | 'itemC' | 'itemD';
type QuantityBasedItem = 'itemA' | 'itemC';
type BooleanBasedItem = Exclude<Item, QuantityBasedItem>;

// 用交叉类型实现条件可选
type MyType<T extends Item> = {
  name: T;
} & (T extends QuantityBasedItem 
  ? { requirements: { units: number } } 
  : { requirements?: undefined });

const getQuantityBasedItemData = (item: QuantityBasedItem, units: number) => ({item, units});
const getBooleanBasedItemData = (item: BooleanBasedItem) => item;

function test<T extends Item>(itemData: MyType<T>) {
  if (itemData.requirements?.units) {
     getQuantityBasedItemData(itemData.name, itemData.requirements)
  } else {
     getBooleanBasedItemData(itemData.name)
  }
}

// 测试用例
test({name: 'itemA', requirements: {units: 5}}); // 正常
test({name: 'itemB'}); // 无需传requirements,正常
test({name: 'itemC', requirements: {units: 10}}); // 正常
test({name: 'itemD'}); // 正常

核心逻辑

两种方法的核心都是将布尔型项的requirements设置为可选属性,TypeScript会自动允许调用时省略该属性。联合类型方案更直观,类型守卫逻辑清晰;条件类型方案保留了泛型结构,适合需要复用MyType的场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 13:46:22