You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让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ś

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.01 22:12:29