React+TypeScript:EventRecord至少含非空时间字段的类型校验问题
解决TypeScript与Remeda结合的类型错误问题
错误原因分析
eventMarked仅返回布尔值,TypeScript无法推断过滤后的EventRecord必然存在至少一个非null的时间字段,导致displayTime仍可能返回null,不符合RemedasortBy要求的可比较类型(Comparable)。- 类型推断链断裂,Remeda的
pipe无法正确识别过滤后数组的类型,最终导致timelineEvents被错误推断为函数类型而非数组,引发map不存在的错误。
具体解决方案
1. 定义带时间约束的子类型并使用类型守卫
创建一个确保至少有一个时间字段非null的子类型,再将eventMarked改为类型守卫函数,让TypeScript明确过滤后的数组元素类型:
// 定义确保至少有一个时间字段非null的EventRecord子类型 type TimedEventRecord = EventRecord & ( { eta: string } | { assumed_time: string } | { indicated_time: string } ); // 类型守卫:返回true时,event被推断为TimedEventRecord export const eventMarked = (event: EventRecord): event is TimedEventRecord => !!(event.assumed_time || event.indicated_time || event.eta);
2. 优化displayTime函数的类型
针对TimedEventRecord重新定义displayTime,确保返回值必然是字符串(无null):
export const displayTime = (event: TimedEventRecord): string => event.indicated_time || event.assumed_time || event.eta;
3. 修正Remeda管道中的类型推断
现在filter后的数组会被TypeScript正确推断为TimedEventRecord[],sortBy接收的displayTime返回可比较的字符串类型,整个管道的类型推断会正常工作:
const timelineEvents = R.pipe( events, R.filter(eventMarked), R.sortBy(displayTime), R.reverse );
4. 优化渲染逻辑
因为timelineEvents的元素是TimedEventRecord,displayTime必然返回字符串,无需再用!强制断言:
{timelineEvents.map((event) => { const time = new Date(displayTime(event)); return ( <RecordContextProvider> <TimelineEntry name={event.name} time={time} /> </RecordContextProvider> ); })}
错误修复说明
- 类型守卫让TypeScript明确过滤后的事件必然有有效时间,解决了
displayTime返回null的类型冲突。 - 优化后的
displayTime返回字符串,符合RemedasortBy要求的Comparable类型,消除了排序时的类型错误。 - 管道的类型推断链恢复正常,
timelineEvents被正确识别为数组类型,map方法可正常调用。
内容的提问来源于stack exchange,提问作者Przemysław Markiewicz
相关产品推荐
相关产品推荐

