如何让Sanity Typegen识别GROQ中$lang动态索引的类型?
Sanity Typegen 无法识别动态$lang索引的类型问题
在Next.js中使用Sanity Typegen时,遇到本地化字段的类型推断问题:运行时通过$lang变量获取对应语言的字符串返回正常,但Typegen生成的类型仍将字段识别为完整的本地化对象,而非单个字符串。
相关代码示例
Schema 定义
defineField({ name: 'title', type: 'object', fields: [ { name: 'pl', type: 'string' }, { name: 'en', type: 'string' } ] })
GROQ 查询
const HERO_QUERY = defineQuery(` *[_type == "home"][0] { "heading": heading[$lang] } `);
生成的类型(types.ts)
export type HERO_QUERY_RESULT = { heading: { pl?: string; en?: string; } | null; };
期望类型
export type HERO_QUERY_RESULT = { heading: string | null; };
问题核心
是否有办法让Sanity Typegen理解$lang动态索引会返回单个字符串?还是必须在组件中每次手动覆写/转换这些类型?(手动覆写可行,但不想通过// @ts-expect-error来忽略报错)
可行解决方案
方案1:使用类型断言封装查询结果
创建通用转换函数,将本地化对象字段转为对应语言的字符串,同时附带类型断言:
type LocalizedString = { pl?: string; en?: string }; const getLocalizedValue = <T extends Record<string, LocalizedString | null>>( data: T, field: keyof T, lang: 'pl' | 'en' ): string | null => { const value = data[field]; return value?.[lang] ?? null; }; // 使用示例 const heroData = await sanityClient.fetch(HERO_QUERY, { lang: 'en' }); const heading = getLocalizedValue(heroData, 'heading', 'en'); // 类型为string | null
方案2:手动标注查询结果类型
先定义本地化字符串基础类型,再手动覆写查询的返回类型:
type Localized<T> = { pl: T; en: T }; type LocalizedString = Localized<string>; // 手动定义期望的查询结果类型 type HeroQueryResult = { heading: string | null; }; // 调用查询时指定类型 const heroData = await sanityClient.fetch<HeroQueryResult>(HERO_QUERY, { lang: 'en' });
方案3:使用Sanity官方localeString类型(推荐)
如果你的Sanity版本支持,改用官方提供的localeString类型替代自定义对象,Typegen能自动识别本地化字段的类型,配合[$lang]索引时会正确推断为字符串:
defineField({ name: 'title', type: 'localeString', // 使用官方本地化字符串类型 })
内容的提问来源于stack exchange,提问作者Jakub Hopciaś
相关产品推荐
相关产品推荐

