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

TypeScript中如何实现TSetTypeArgument以正确指定泛型参数?

TypeScript泛型包装类型的参数替换实现

需求说明

现有不可修改的基础TypeScript类型:

type TProps<TK extends string, T> = { a: TK; b: T };

需要为其创建包装类型TWrap,要求在根层级指定TK,在字段层级指定T。由于TypeScript不允许为类型字段直接添加泛型参数,因此采用函数包装的方式实现:

type TWrap<TR> = {
  func: <T>() => TProps<TR, T>;
  otherFunc: <T>() => TOtherProps<TR, T>;
  // 省略其他类型字段
}

尝试方案及问题

尝试编写TSetTypeArgument类型来实现参数替换,但未达到预期效果:

type tf<R> = () => R;
type to<A1,A2> = {};

type TSetTypeArgument<T, A> = T extends tf<infer R>
    ? R extends to<infer X, infer Y> // 1
      ? to<X, A> & R                 // 2  
      : never
    : never;

type TRes = TSetTypeArgument<TWrap['func'], number>;

测试时发现变量b的类型为unknown,而非预期的number:

const t3: TRes = { a: '', b: 7 };
const b = t3.b; // 预期b为number,实际为unknown

实际使用场景

  • application-api.ts:
export type makeApplicationApi<TLocale, TState, TAction> = {
  form: <TForm>() => TProps<TLocale, TForm>;
  request: <TRequest>() => TOtherProps<TLocale, TRequest>;
  // ...
  selector: (state: TState, action: TAction) => string | number;
}
  • orders-api.ts:
type TAppTypes = makeApplicationApi<TOrderLocale, TOrderState, TOrderAction>;

export type TOrderForm = TSetTypeArgument<TAppTypes['form'], TOrderFormsDictionary>;
export type TOrderRequest = TSetTypeArgument<TAppTypes['request'], TOrderRequestsDictionary>;
export type TOrderSelector = TAppTypes['selector'];

可行解决方案

要实现正确的参数替换,需要精准匹配函数返回的泛型类型结构,提取已固定的第一个泛型参数,再将第二个泛型参数替换为指定类型。以下是修正后的TSetTypeArgument类型:

针对特定类型的实现

如果只需要处理TProps和TOtherProps这类结构一致的类型,可以直接匹配:

type TSetTypeArgument<T, A> = 
  // 匹配返回TProps的函数
  T extends <TIn>() => TProps<infer TK, infer _> 
    ? TProps<TK, A> 
    : // 匹配返回TOtherProps的函数
      T extends <TIn>() => TOtherProps<infer TK, infer _> 
        ? TOtherProps<TK, A> 
        : never;

通用化实现

如果有更多类似的双泛型参数类型,可以通过匹配类型结构来实现通用替换:

type TSetTypeArgument<T, A> = 
  T extends <TIn>() => infer R
    ? R extends { a: infer TK, b: infer _ } // 匹配TProps的结构
      ? { a: TK, b: A }
      : R extends { /* 这里填入TOtherProps的结构特征 */ }
        ? { /* 对应替换TOtherProps的第二个参数 */ }
        : never
    : never;

测试修正后的类型:

type TRes = TSetTypeArgument<TWrap['func'], number>;
const t3: TRes = { a: 'test', b: 7 };
const b = t3.b; // 现在b的类型为number,符合预期

说明

原方案的问题在于使用了空的to类型进行匹配,无法正确关联到TProps的实际结构,导致类型推断失败。修正后的方案直接匹配目标类型的结构或泛型参数定义,确保能正确提取并替换指定的泛型参数。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 19:18:23