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

TypeScript基础:从含字符串的对象中动态调用函数

解决TypeScript中I18n工具调用函数式翻译项的报错问题

问题场景

调用i18n.t("signed_in_as")("Chris")时出现TypeScript报错,错误信息:

This expression is not callable.
Not all constituents of type '"Your bus tickets" | "Deine Bustickets" | ((user: string) => string) | ""' are callable.
Type '"Your bus tickets"' has no call signatures.ts(2349)

原代码如下:

const prompts = {
  bus_tickets: {
    en: 'Your bus tickets',
    de: 'Deine Bustickets',
  },
  signed_in_as: {
    en: (user: string) => `Signed in as: ${user}`,
    de: (user: string) => `Eingeloggt als: ${user}`,
  },
} as const

type TranslationKey = keyof typeof prompts

class I18n {
  userLocale: 'en' | 'de'

  constructor(userLocale: 'en' | 'de') {
    this.userLocale = userLocale
  }

  t(translationKey: TranslationKey) {
    const translations = prompts[translationKey]
    if (translations) return translations[this.userLocale]
    return ''
  }
}

// 报错的调用
const i18n = new I18n("en")
i18n.t("signed_in_as")("Chris") // ERROR!

报错原因

当前I18n.t方法的返回类型是所有翻译项的联合类型——包含字符串(如bus_tickets的翻译值)和函数(如signed_in_as的翻译函数)。TypeScript无法确定调用t("signed_in_as")返回的是可调用的函数,因此抛出错误,因为联合类型中存在不可调用的字符串类型。

解决方案

通过泛型让t方法根据传入的translationKey精确推断返回类型,修改后的代码如下:

const prompts = {
  bus_tickets: {
    en: 'Your bus tickets',
    de: 'Deine Bustickets',
  },
  signed_in_as: {
    en: (user: string) => `Signed in as: ${user}`,
    de: (user: string) => `Eingeloggt als: ${user}`,
  },
} as const

type TranslationKey = keyof typeof prompts

class I18n {
  userLocale: 'en' | 'de'

  constructor(userLocale: 'en' | 'de') {
    this.userLocale = userLocale
  }

  // 用泛型K捕获具体的translationKey类型,精确返回对应翻译值的类型
  t<K extends TranslationKey>(translationKey: K): typeof prompts[K][typeof this.userLocale] {
    const translations = prompts[translationKey]
    if (translations) return translations[this.userLocale]
    return '' as never // 断言为never,避免类型不匹配(实际不会执行到这里)
  }
}

// 现在可以正常调用
const i18n = new I18n("en")
i18n.t("signed_in_as")("Chris") // 正常运行
console.log(i18n.t("bus_tickets")) // 输出 "Your bus tickets"

补充:不推荐的临时方案

如果不想修改t方法的类型定义,也可以用类型断言强制指定返回类型,但这种方式不安全,容易引发潜在错误:

(i18n.t("signed_in_as") as (user: string) => string)("Chris")

内容的提问来源于stack exchange,提问作者christianbauer1

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 13:02:34