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

TypeScript动态调用方法时扩展运算符类型报错问题咨询

问题:TypeScript调用Android桥接方法时的参数展开报错

我定义了AndroidInterface接口,描述通过JS桥暴露在window对象的androidInterfaceMethods上的方法签名:

interface AndroidInterface {
  getXo: () => string | null;
  getOx: () => string | null;
  saveXo: (xo: string) => void;
  saveOx: (ox: string) => void;
  getGaid: () => string | null;
  sendAnalyticsEvents: (
    eventName: string,
    eventProperties: Record<string, unknown>
  ) => void;
  getAppVersionCode: () => number | null;
  getClientId: () => string | null;
  getConfig: () => Record<string, unknown> | null;
  isFirstAppLogin: () => boolean;
  logout: () => void;
  openWhatsapp: (message: string, phone: string) => void;
}

同时扩展Window接口:

interface Window{
 androidInterfaceMethods?: AndroidInterface;
}

编写泛型函数invokeAndroidInterface动态调用这些方法:

const invokeAndroidInterface = <K extends keyof AndroidInterface>(
  methodName: K,
  ...args: Parameters<AndroidInterface[K]>
): ReturnType<AndroidInterface[K]> | null => {
 
  if (typeof window !== "undefined" && window.androidInterfaceMethods) {
    const method = window.androidInterfaceMethods[methodName];
    if (typeof method === "function") {
        return method(...args);
    }
  }
  return null
}

但method(...args)处报错:A spread argument must either have a tuple type or be passed to a rest parameter. 希望TypeScript自动推断函数签名,不想用类型断言,尝试普通类型守卫无效,硬编码或断言可解决但不够严谨,求合理方案。

解决方案

问题根源在于使用typeof method === "function"时,TypeScript会将method的类型缩小为宽泛的Function类型,丢失了其对应AndroidInterface[K]的具体参数和返回类型信息,导致无法匹配args的Parameters<AndroidInterface[K]>元组类型。

方案1:利用接口约束直接调用

由于AndroidInterface的所有属性都被定义为函数类型,只要window.androidInterfaceMethods符合接口定义,method必然是对应类型的函数。可以移除typeof method === "function"的判断,直接调用:

const invokeAndroidInterface = <K extends keyof AndroidInterface>(
  methodName: K,
  ...args: Parameters<AndroidInterface[K]>
): ReturnType<AndroidInterface[K]> | null => {
  if (typeof window !== "undefined" && window.androidInterfaceMethods) {
    const method = window.androidInterfaceMethods[methodName];
    return method(...args);
  }
  return null;
};

方案2:自定义类型守卫保留具体类型

如果需要运行时校验方法是否为函数,可编写自定义类型守卫,让TypeScript保留method的具体函数类型:

// 自定义类型守卫,确认方法是对应K的函数类型
function isAndroidInterfaceMethod<K extends keyof AndroidInterface>(
  method: unknown,
  _methodName: K
): method is AndroidInterface[K] {
  return typeof method === "function";
}

const invokeAndroidInterface = <K extends keyof AndroidInterface>(
  methodName: K,
  ...args: Parameters<AndroidInterface[K]>
): ReturnType<AndroidInterface[K]> | null => {
  if (typeof window !== "undefined" && window.androidInterfaceMethods) {
    const method = window.androidInterfaceMethods[methodName];
    if (isAndroidInterfaceMethod(method, methodName)) {
      return method(...args);
    }
  }
  return null;
};

两种方案都能让TypeScript自动推断函数签名,无需类型断言,既保证类型安全,又解决了参数展开的报错问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 11:33:10