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

TypeScript:如何定义参数继承Container的泛型函数且不使用any?

问题:如何指定泛型函数类型,使其参数继承Container且不使用any?

函数参数具有逆变特性,返回值具有协变特性。现在需要指定一个泛型函数类型,让它的参数继承Container类型且不使用any。当前代码调用process(processFn)时会报错,想知道怎么修正类型声明:

type Container<V> = {
  id: string;
  join: (value: V) => void;
};

const process = <V extends Container<unknown>>(processFn: (container: V) => boolean) => {
  // do something with processFn
}

type ExtendedContainer = Container<number> & { status: string; };
const processFn = (container: ExtendedContainer) => {
  return true;
}

process(processFn); // 此处报错

报错原因分析

当前process的泛型约束是V extends Container<unknown>,TypeScript会将V推断为最宽泛的Container<unknown>,但传入的processFn参数类型是更具体的ExtendedContainer(Container<number>的扩展类型)。由于函数参数的逆变特性,要求函数参数类型必须“更宽泛”才能兼容,而ExtendedContainer比Container<unknown>更具体,因此类型不匹配导致报错。

解决方案

方案1:拆分泛型参数,明确Container的类型参数与扩展类型

通过两个泛型参数分别约束Container的类型参数T,以及继承自Container<T>的扩展类型C,让TypeScript能准确推断具体类型:

type Container<V> = {
  id: string;
  join: (value: V) => void;
};

// T对应Container的类型参数,C是扩展Container<T>的具体类型
const process = <T, C extends Container<T>>(processFn: (container: C) => boolean) => {
  // do something with processFn
}

type ExtendedContainer = Container<number> & { status: string; };
const processFn = (container: ExtendedContainer) => {
  return true;
}

process(processFn); // 无报错,T被推断为number,C被推断为ExtendedContainer

方案2:利用逆变特性,直接约束参数为Container的子类型

更简洁的写法:只声明Container的类型参数T,利用逆变特性允许processFn的参数是Container<T>的任意子类型(逆变允许更具体的参数类型赋值给更宽泛的参数类型):

type Container<V> = {
  id: string;
  join: (value: V) => void;
};

// T对应Container的类型参数,processFn的参数可以是Container<T>的任意子类型
const process = <T>(processFn: (container: Container<T>) => boolean) => {
  // do something with processFn
}

type ExtendedContainer = Container<number> & { status: string; };
const processFn = (container: ExtendedContainer) => {
  return true;
}

process(processFn); // 无报错,T被推断为number,ExtendedContainer是Container<number>的子类型,符合逆变规则

方案2的核心逻辑是:如果类型A是类型B的子类型,那么(a: A) => R可以赋值给(b: B) => R(逆变特性)。这里ExtendedContainer是Container<number>的子类型,因此对应的函数类型自然兼容(container: Container<number>) => boolean,TypeScript能自动完成类型推断。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 00:43:17