TypeScript中如何类型安全处理含多类型Route的Quote实体?
解决方案:安全处理联合类型的Quote实体
1. 用自定义类型守卫区分路线类型
要安全处理RailRoute和CarRoute的联合类型,最可靠的方式是自定义类型守卫,通过类型谓词让TypeScript自动推断类型,无需手动断言。
先明确基础类型定义:
interface RailRoute { type: 'rail'; trainNumber: string; departureStation: string; } interface CarRoute { type: 'car'; licensePlate: string; driverName: string; } type Quote = { id: string; price: number; route: RailRoute | CarRoute; };
编写类型守卫函数:
// 判断是否为铁路路线 function isRailRoute(route: RailRoute | CarRoute): route is RailRoute { return route.type === 'rail'; } // 判断是否为汽车路线 function isCarRoute(route: RailRoute | CarRoute): route is CarRoute { return route.type === 'car'; }
在handleQuote中使用类型守卫:
function handleQuote(quote: Quote) { console.log(`报价ID: ${quote.id}, 价格: ${quote.price}`); if (isRailRoute(quote.route)) { // TypeScript自动推断quote.route为RailRoute,可直接访问专属字段 console.log(`铁路车次: ${quote.route.trainNumber}, 出发站: ${quote.route.departureStation}`); } else if (isCarRoute(quote.route)) { // 自动推断为CarRoute,安全访问车牌、司机字段 console.log(`汽车车牌: ${quote.route.licensePlate}, 司机: ${quote.route.driverName}`); } else { // 兜底处理,避免未来新增路线类型时出现未覆盖逻辑 throw new Error(`未知路线类型: ${JSON.stringify(quote.route)}`); } }
2. 优化代码结构:拆分类型处理逻辑
如果handleQuote内逻辑复杂,可将不同路线的处理逻辑拆分为独立函数,提升代码可读性和可维护性:
// 单独处理铁路路线逻辑 function handleRailRoute(route: RailRoute) { console.log(`铁路车次: ${route.trainNumber}, 出发站: ${route.departureStation}`); // 可添加更多铁路专属业务逻辑 } // 单独处理汽车路线逻辑 function handleCarRoute(route: CarRoute) { console.log(`汽车车牌: ${route.licensePlate}, 司机: ${route.driverName}`); // 可添加更多汽车专属业务逻辑 } function handleQuote(quote: Quote) { console.log(`报价ID: ${quote.id}, 价格: ${quote.price}`); if (isRailRoute(quote.route)) { handleRailRoute(quote.route); } else if (isCarRoute(quote.route)) { handleCarRoute(quote.route); } else { throw new Error(`未知路线类型: ${JSON.stringify(quote.route)}`); } }
3. API数据类型安全:无需断言的校验逻辑
从API获取数据时,不能直接通过类型断言强转,需结合运行时校验确保数据符合类型定义,同时让TypeScript自动推断类型。
编写完整的Quote校验函数:
function isValidQuote(data: unknown): data is Quote { // 先校验基础结构 if (typeof data !== 'object' || data === null) return false; const quote = data as Quote; // 校验Quote的基础字段 if (typeof quote.id !== 'string' || typeof quote.price !== 'number') return false; // 校验route字段的结构和类型 const route = quote.route; if (typeof route !== 'object' || route === null || !('type' in route)) return false; // 根据type字段校验对应类型的专属属性 switch (route.type) { case 'rail': return typeof route.trainNumber === 'string' && typeof route.departureStation === 'string'; case 'car': return typeof route.licensePlate === 'string' && typeof route.driverName === 'string'; default: return false; } }
在API请求中使用校验:
async function fetchQuote(id: string): Promise<Quote> { const response = await fetch(`/api/quotes/${id}`); const rawData = await response.json(); if (!isValidQuote(rawData)) { throw new Error('API返回的报价数据格式不符合要求'); } // 此时rawData已被自动推断为Quote类型,无需任何断言 return rawData; }
后续调用fetchQuote后,可直接将结果传入handleQuote,全程无需手动断言类型。
内容的提问来源于stack exchange,提问作者undefined
相关产品推荐
相关产品推荐

