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

TypeScript中省略泛型类型为何为对象?相关疑问咨询

Great question! Let's break this down into two clear parts: why TypeScript defaults unspecified generics to {} instead of any, and how to enforce explicit generic type arguments for your classes.


Why the default is {} instead of any

First, it’s critical to distinguish {} from any—they behave very differently:

  • any completely opts out of TypeScript’s type checking. You can call arbitrary methods, assign values of any type, and access non-existent properties without compile-time warnings.
  • {} is the broadest object type available. It accepts any value that is (or can be coerced to) an object, but still enforces basic type safety—for example, you’ll get a warning if you try to call a method that doesn’t exist on {}.

The TypeScript team chose {} as the default for unbound generics for three key reasons:

  • Prioritize type safety by default: They wanted to avoid implicitly enabling the "no checks" behavior of any unless developers explicitly ask for it. {} keeps some guardrails in place while remaining flexible for untyped use cases.
  • Backward compatibility: Early versions of TypeScript used {} as the default for unspecified generics. Changing this to any would break existing codebases that rely on this behavior.
  • Philosophical alignment: TypeScript’s core goal is to add static typing to JavaScript without getting in the way. {} strikes a balance—it’s permissive enough to work with most unplanned use cases, but still catches obvious mistakes that any would ignore.

Your guess about "T belonging to class object types" is partially correct, but this behavior applies to all generics (not just classes). For example, a generic function like function getValue<T>(): T { return {} as T; } will return a value of type {} when called without a type argument, not any.


How to enforce explicit generic type arguments

If you want to ensure developers can’t instantiate your generic class without specifying (or letting TypeScript infer) a type for T, here are two reliable approaches:

1. Add a constructor parameter of type T

The simplest method is to require a value of type T in the constructor. This forces TypeScript to either infer T from the argument or throw an error if no argument is provided (since it can’t guess T). Example:

class Foo<T> {
  constructor(private value: T) {}
}

// ❌ Error: Unable to infer type argument(s) for Foo<T>
const badFoo = new Foo();

// ✅ OK: T is inferred as string from the argument
const goodFoo1 = new Foo("hello");

// ✅ OK: Explicitly specify T as number
const goodFoo2 = new Foo<number>(42);

2. Use a compile-time check for the default {} type

If your class doesn’t need a constructor parameter, you can add a hacky but effective compile-time check to block instantiation with the default {} type. This uses conditional types to throw an error when T is the default:

class Foo<T> {
  constructor() {
    // If T is the default {}, this will fail to compile
    type MustSpecifyType = T extends {} ? never : T;
    // @ts-expect-error: Forces error when T is {}
    const _check: MustSpecifyType = {} as any;
  }
}

// ❌ Error: Type '{}' is not assignable to type 'never'
const badFoo = new Foo();

// ✅ OK: Explicitly specify T
const goodFoo = new Foo<string>();

Note that there’s no built-in TypeScript compiler option to enforce explicit generic types globally—you’ll need to implement these checks per class.


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.11 09:13:26