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

TypeScript装饰器泛型类型变为unknown问题求助

解决方案

问题分析

两次尝试的核心问题:

  • 第一次未正确推导原函数的返回值类型,导致Result的value为unknown;
  • 第二次错误地将Promise<string>直接放入Result,而非解析后的string类型。

正确实现代码

首先明确Result类型定义:

type Result<T, E> = { ok: true; value: T } | { ok: false; error: E };

实现带重试功能且返回Promise<Result<T, Error>>的装饰器:

import { retryDecorator, RetryConfig } from "ts-retry-promise";

function retryWithResult<TArgs extends any[], T>(
  config?: RetryConfig
): (fn: (...args: TArgs) => Promise<T>) => (...args: TArgs) => Promise<Result<T, Error>> {
  return (fn) => {
    // 先通过retryDecorator添加重试逻辑
    const retriedFn = retryDecorator(config)(fn);
    
    // 包裹一层处理Result类型转换
    return async (...args) => {
      try {
        const value = await retriedFn(...args);
        return { ok: true, value };
      } catch (error) {
        return { ok: false, error: error instanceof Error ? error : new Error(String(error)) };
      }
    };
  };
}

关键说明

  1. 泛型捕获类型:通过TArgs(原函数参数类型)和T(原函数Promise解析后的返回值类型),让TypeScript能正确推导最终Result的类型;
  2. 分层包装:先借助retryDecorator实现重试逻辑,再通过async/await解析Promise结果,最后用try/catch将成功值或错误包装为Result类型;
  3. 错误处理:确保捕获的错误始终是Error类型,避免非Error值导致的类型问题。

使用示例

// 原异步函数
async function fetchData(a: string): Promise<string> {
  if (Math.random() > 0.5) throw new Error("Fetch failed");
  return `Data for ${a}`;
}

// 用装饰器包装后,类型为:(a: string) => Promise<Result<string, Error>>
const retryFetchData = retryWithResult({ retries: 2 })(fetchData);

// 使用时类型完全正确
async function test() {
  const result = await retryFetchData("test");
  if (result.ok) {
    console.log(result.value); // 类型为string
  } else {
    console.error(result.error); // 类型为Error
  }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 06:50:30