如何传递Remix useLoaderData返回的JsonifyObject<T>并解决类型错误
解决Remix 2.9.2中JsonifyObject类型兼容问题
自定义Jsonify类型替代未导出的内部类型
Remix的JsonifyObject是未对外导出的内部类型,无法直接导入。你可以自己实现一个逻辑完全一致的Jsonify类型,用来描述序列化后的数据结构:
type Jsonify<T> = T extends Date ? string // Date对象序列化后会变成ISO格式字符串 : T extends object ? { [K in keyof T]: Jsonify<T[K]> } // 递归处理嵌套对象 : T extends undefined | null | boolean | number | string ? T // 基础类型保持原类型 : never;
之后你可以用这个类型约束useLoaderData的返回值,或者直接调整formatIdAndDate的参数类型为Jsonify<IdAndDate>,这样既不会丢失date为字符串的类型提示,也能通过TypeScript检查:
// 调整格式化函数的参数类型 function formatIdAndDate(data: Jsonify<IdAndDate>) { // 此时data.date类型明确为string,直接转换为Date处理 const formattedDate = new Date(data.date).toLocaleString(); return `${data.id}: ${formattedDate}`; } // 组件中直接使用,无需类型断言 const data = useLoaderData<typeof loader>() as Jsonify<IdAndDate>; formatIdAndDate(data);
让格式化函数兼容原始与序列化两种类型
如果需要formatIdAndDate同时支持服务端的原始IdAndDate类型和客户端的序列化后类型,可以将参数设为联合类型,并在内部做类型判断:
function formatIdAndDate(data: IdAndDate | Jsonify<IdAndDate>) { // 统一处理date:如果是字符串则转为Date,否则直接使用 const targetDate = typeof data.date === 'string' ? new Date(data.date) : data.date; return `${data.id} - ${targetDate.toLocaleDateString('zh-CN')}`; } // 组件中直接传入useLoaderData返回值,无类型错误 const data = useLoaderData<typeof loader>(); formatIdAndDate(data);
使用类型守卫做安全类型校验
如果不想修改格式化函数,也可以通过类型守卫来确认数据结构,确保类型安全的同时保留类型提示:
// 定义类型守卫,校验数据是否为序列化后的IdAndDate function isJsonifiedIdAndDate(data: unknown): data is Jsonify<IdAndDate> { return ( typeof data === 'object' && data !== null && 'id' in data && typeof (data as any).id === 'string' && 'date' in data && typeof (data as any).date === 'string' ); } // 组件中使用 const data = useLoaderData<typeof loader>(); if (isJsonifiedIdAndDate(data)) { // 此处data类型被正确推断为Jsonify<IdAndDate>,可安全传入格式化函数 formatIdAndDate(data as IdAndDate); // 若函数未修改参数类型,此处断言安全且保留类型提示 }
内容的提问来源于stack exchange,提问作者rickjoi
相关产品推荐
相关产品推荐

