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

开启strictFunctionTypes=true时,如何避免TypeScript对泛型类实例的类型推断过窄?

Great question! The issue here boils down to how TypeScript infers generic types when strictFunctionTypes is enabled—since your Foo class has a function parameter that uses Foo<T> in a contravariant position (function arguments are contravariant under strict mode), TypeScript locks in the literal type 5 for T instead of widening it to number.

Let's look at some clean, maintainable solutions that keep strictFunctionTypes enabled without needing explicit generic type annotations every time:

Solution 1: Reorder Constructor Parameters

TypeScript infers generic types based on the order of arguments. By moving the fn parameter first, TypeScript will prioritize inferring T from the function's type annotation (Foo<number>) instead of the literal 5:

class Foo<T> {
  constructor(
    public fn: (value: Foo<T>) => void,
    public value: T
  ) {}
}

// Now T is inferred as number automatically
const foo = new Foo((v: Foo<number>) => {}, 5);
foo.value = 100; // No error!

Solution 2: Use a Static Factory Method

If reordering constructor parameters doesn't fit your API design, a static factory method can guide type inference the same way, while keeping your constructor parameter order intact:

class Foo<T> {
  constructor(public value: T, public fn: (value: Foo<T>) => void) {}

  // Factory method prioritizes inferring T from the fn parameter
  static create<T>(fn: (value: Foo<T>) => void, value: T): Foo<T> {
    return new Foo(value, fn);
  }
}

const foo = Foo.create((v: Foo<number>) => {}, 5);
foo.value = 100; // Works perfectly

Solution 3: Widen the Literal Type (Lightweight Annotation)

If you prefer to keep the original constructor order, you can use a type assertion to widen the literal 5 to number—this is a minimal annotation that's less verbose than explicitly specifying Foo<number>:

class Foo<T> {
  constructor(public value: T, public fn: (value: Foo<T>) => void) {}
}

const foo = new Foo(5 as number, (v: Foo<number>) => {});
foo.value = 100; // No error

Why These Work

When strictFunctionTypes is enabled, TypeScript enforces stricter contravariance for function parameters. By guiding TypeScript to infer T from the fn parameter (which explicitly uses Foo<number>) instead of the literal value, we ensure T is widened to number rather than being locked to the literal 5.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 07:02:37