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

如何实现接收Lambda及命名参数的TypeScript函数?

实现支持Lambda函数+结构化参数的通用函数(适配React请求钩子场景)

核心思路

针对你需要的foo(lambdaFn, { param1: "test", param2: 1})调用方式,通过泛型约束Lambda的参数类型,让第二个参数与Lambda的入参结构强绑定,同时预留独立的配置参数位,既解决参数关联性问题,又满足后续扩展需求。

基础通用函数实现

先定义基础的通用函数,适配Lambda+结构化参数的调用模式:

// 定义接收结构化参数的异步处理器类型
type AsyncHandler<TParams extends object, TResult> = (params: TParams) => Promise<TResult>;

function execute<TParams extends object, TResult>(
  handler: AsyncHandler<TParams, TResult>,
  params: TParams,
  config?: {
    // 这里可以添加任意扩展配置,比如超时、请求标识等
    timeout?: number;
    requestId?: string;
  }
): Promise<TResult> {
  // 统一处理配置逻辑(比如超时包装、请求日志)
  const wrappedHandler = async () => {
    const controller = new AbortController();
    const timeoutId = config?.timeout && setTimeout(() => controller.abort(), config.timeout);
    
    try {
      return await handler(params);
    } finally {
      clearTimeout(timeoutId);
    }
  };

  return wrappedHandler();
}

// 使用示例
const getPosts = async (params: { category: string; page: number }) => {
  const res = await fetch(`/api/posts?category=${params.category}&page=${params.page}`);
  return res.json();
};

// 调用时参数类型完全匹配,IDE自动提示
execute(getPosts, { category: "tech", page: 1 }, { timeout: 5000 });

扩展到React自定义请求钩子

基于上述思路,封装符合需求的React网络请求钩子,统一管理请求状态:

import { useState, useEffect, useCallback } from 'react';

// 定义请求配置项
type RequestHookConfig = {
  enabled?: boolean; // 是否自动触发初始请求
  onSuccess?: (data: any) => void;
  onError?: (error: Error) => void;
};

function useRequest<TParams extends object, TResult>(
  requestFn: (params: TParams) => Promise<TResult>,
  initialParams: TParams,
  config?: RequestHookConfig
) {
  const [data, setData] = useState<TResult | null>(null);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<Error | null>(null);

  const fetchData = useCallback(async (params: TParams) => {
    setLoading(true);
    setError(null);
    try {
      const result = await requestFn(params);
      setData(result);
      config?.onSuccess?.(result);
    } catch (err) {
      const errorObj = err as Error;
      setError(errorObj);
      config?.onError?.(errorObj);
    } finally {
      setLoading(false);
    }
  }, [requestFn, config]);

  // 自动触发初始请求(可通过enabled配置关闭)
  useEffect(() => {
    if (config?.enabled !== false) {
      fetchData(initialParams);
    }
  }, [initialParams, fetchData, config?.enabled]);

  return {
    data,
    loading,
    error,
    refetch: fetchData // 手动触发请求的方法
  };
}

// 钩子使用示例
const fetchUser = async (params: { userId: number; includeProfile: boolean }) => {
  const res = await fetch(`/api/users/${params.userId}?includeProfile=${params.includeProfile}`);
  if (!res.ok) throw new Error('Failed to fetch user');
  return res.json();
};

function UserPage() {
  const { data, loading, error, refetch } = useRequest(
    fetchUser,
    { userId: 456, includeProfile: true },
    {
      enabled: true,
      onSuccess: (user) => console.log('User loaded:', user),
      onError: (err) => console.error('Fetch error:', err)
    }
  );

  if (loading) return <div>Loading user data...</div>;
  if (error) return <div>Error: {error.message}</div>;

  return (
    <div>
      <h2>{data?.username}</h2>
      <button onClick={() => refetch({ userId: 456, includeProfile: false })}>Hide Profile</button>
    </div>
  );
}

方案优势

  • 参数强关联:通过泛型约束,结构化参数与Lambda入参类型完全匹配,IDE能提供精准的类型提示,避免参数错误
  • 可扩展性强:独立的config参数位可以自由添加超时控制、请求拦截、回调函数等扩展逻辑,不影响核心调用方式
  • 状态统一管理:React钩子版本封装了加载、错误、数据状态,无需在组件中重复编写状态逻辑

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 10:27:45