TypeScript中FeeReturnType类型为何无法被正确推导?
TypeScript类型收窄问题解决:让data自动匹配对应类型
问题根源
你定义的FeeReturnType<T>是条件类型,但在handleFeeData函数内部,泛型T是未具体化的类型参数——TypeScript没办法通过switch (_type)的分支来推断T的具体值,所以data始终是所有可能类型的联合,导致访问分支专属属性时无法获得正确的类型提示或出现报错。
最优解决方案:用区分联合类型重构参数
把类型标识和数据合并成一个带区分字段的联合对象,让TypeScript自动完成类型收窄:
export type FeeType = 'ALL' | 'API' | 'FILE' | 'DATA_SVR' | 'ACCOUNT'; export interface AllFee { name: string; fee: number; } export interface ApiOrFileFee { integrator_id: string; integrator_name: string; call_count: number; fee: number; } export interface DataSvrFee { integrator_id: string; integrator_name: string; count: number; fee: number; } export interface AccountFee { name: string; id: string; count: string; user: string; user_id: string; fee: number; } // 定义区分联合类型,每个子类型用type字段做标识 type FeeData = | { type: 'ALL'; data: AllFee[] } | { type: 'API' | 'FILE'; data: ApiOrFileFee[] } | { type: 'DATA_SVR'; data: DataSvrFee[] } | { type: 'ACCOUNT'; data: AccountFee[] }; function handleFeeData(feeData: FeeData): void { switch (feeData.type) { case 'ALL': feeData.data.forEach(item => { console.log('All Fee:', item.name, item.fee); }); break; case 'API': case 'FILE': feeData.data.forEach(item => { console.log('API/File Fee:', item.integrator_id, item.call_count, item.fee); }); break; case 'DATA_SVR': feeData.data.forEach(item => { console.log('Data Svr Fee:', item.integrator_id, item.count, item.fee); }); break; case 'ACCOUNT': feeData.data.forEach(item => { console.log('Account Fee:', item.name, item.user, item.fee); }); break; default: break; } } // 调用方式调整为传入带type的对象 const allFeeData: AllFee[] = [{ name: 'All Fee', fee: 100 }]; const apiFeeData: ApiOrFileFee[] = [{ integrator_id: '123', integrator_name: 'API Integrator', call_count: 10, fee: 50 }]; const accountFeeData: AccountFee[] = [{ name: 'Account', id: '1', count: '10', user: 'John', user_id: '100', fee: 200 }]; handleFeeData({ type: 'ALL', data: allFeeData }); handleFeeData({ type: 'API', data: apiFeeData }); handleFeeData({ type: 'ACCOUNT', data: accountFeeData });
这种方式利用TypeScript的区分联合类型特性,当你在switch中匹配feeData.type时,编译器会自动把feeData.data的类型收窄到对应分支的具体类型,完全不需要手动断言。
备选方案:手动类型断言(不推荐)
如果不想改动参数结构,可以在每个分支里给data加类型断言,但这种方式需要手动维护类型一致性,容易出错:
function handleFeeData<T extends FeeType>(_type: T, data: FeeReturnType<T>): void { switch (_type) { case 'ALL': (data as AllFee[]).forEach(item => { console.log('All Fee:', item.name, item.fee); }); break; case 'API': case 'FILE': (data as ApiOrFileFee[]).forEach(item => { console.log('API/File Fee:', item.integrator_id, item.call_count, item.fee); }); break; case 'DATA_SVR': (data as DataSvrFee[]).forEach(item => { console.log('Data Svr Fee:', item.integrator_id, item.count, item.fee); }); break; case 'ACCOUNT': (data as AccountFee[]).forEach(item => { console.log('Account Fee:', item.name, item.user, item.fee); }); break; default: break; } }
内容的提问来源于stack exchange,提问作者Hoon
相关产品推荐
相关产品推荐

