【问题标题】:Why is it possible to instantiate a generic class without having specified the generic type parameter为什么可以在没有指定泛型类型参数的情况下实例化泛型类
【发布时间】:2021-03-06 08:18:27
【问题描述】:

我不明白为什么 TypeScript 允许在没有指定实际的泛型类型参数的情况下实例化泛型类? 在以下示例中,类Foo 有一个泛型类型参数T。 在const foo = new Foo() 行中,可以创建一个新的foo 对象,而无需指定泛型类型参数。 foo 的类型为 Foo<unknown>bar 的类型为 valueType<unknown>

为什么可能并且 TypeScript 不会引发错误? 这是什么用例? TypeScript 是否可以强制要求泛型类型参数?

type valueType<T> = {
   name: string,
   key: T|null,
};

class Foo<T> {
   private value: valueType<T>;

   public constructor() {
      this.value = {
         name: '',
         key: null,
      };
   }

   public setValue(value: valueType<T>) {
      this.value = value;
   }

   public getValue(): valueType<T> {
      return this.value;
   }
}

const foo = new Foo();
const bar = foo.getValue();

Typescript Playground Link

【问题讨论】:

    标签: typescript class generics typescript-generics


    【解决方案1】:

    在其他similar threads 中推荐的合理选项是默认为never 类型。这无疑会导致进一步的问题,因为never 类型不能用于任何有意义的事情,所以你的类的调用者会意识到他们做错了什么,他们需要将类型参数传递给 Foo。

    type valueType<T> = {
       name: string,
       key: T|null,
    };
    
    class Foo<T = never> {
       private value: valueType<T>;
    
       public constructor() {
          this.value = {
             name: '',
             key: null,
          };
       }
    
       public setValue(value: valueType<T>) {
          this.value = value;
       }
    
       public getValue(): valueType<T> {
          return this.value;
       }
    }
    
    const foo = new Foo();
    // bar will now have the `never` type, making it unusable
    const bar = foo.getValue();
    

    【讨论】:

      【解决方案2】:

      我不明白为什么 TypeScript 允许在没有指定实际泛型类型参数的情况下实例化泛型类?

      在大多数情况下,泛型可以从参数中推断出来。在这种情况下,没有参数,因此必须明确设置或变为unknown

      假设我们修改了我们的构造函数,使其接受T 类型的key 作为参数。

      public constructor(key: T) {
      

      现在 typescript 会自动将我们实例的泛型变量分配给我们传递给构造函数的 key 参数的类型。我们不需要写new Foo&lt;string&gt;('x')。我们可以写new Foo('x') 得到Foo&lt;string&gt;

      TypeScript 是否可以强制要求泛型类型参数?

      我不这么认为,但我不确定。这将是您的 tsconfig 或 linter 中的内容。

      如果您要求每个 泛型函数或类都需要明确声明的泛型,那么这将很快变得非常烦人。类型推断是打字稿的基石之一。您只想在它被推断为unknown 的情况下需要它。

      您通常会看到泛型函数和类为泛型设置默认值,当无法推断时使用该默认值。 unknown 会产生问题,但 any 会起作用(只是不是很有帮助)。没有任何东西可以分配给unknown,但所有东西都可以分配给any。您可以将any 设置为默认值:

      class Foo<T = any> {
      

      现在,当您拨打new Foo() 时,您会收到Foo&lt;any&gt;

      【讨论】:

      • 我完全理解 TypeScript 会在可能的情况下从参数中推断出来,但是如果没有什么可以推断出来的——就像我的例子一样。使用unknown而不是告诉我没有明确的类型参数并且无法推断类型真的有意义吗?
      • 设置 —noGenericUnknown 或 —noInferredUnknown 并不是一个疯狂的想法。我认为目前不存在这样的事情,但我可能是错的。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-10-13
      • 1970-01-01
      • 2015-10-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多