【问题标题】:TypeScript generics - Conditionally set parameter of a generic interface type with an implementation class object as valueTypeScript 泛型 - 以实现类对象作为值有条件地设置泛型接口类型的参数
【发布时间】:2021-06-14 13:25:19
【问题描述】:
interface myGenericInterface<T> {
    propX : T;
}

class implementationA implements myGenericInterface<string> {
    propX : string;
}

class implementationB implements myGenericInterface<number> {
    propX : number;
}

class sample<T> {
    prop : myGenericInterface<T>;

    constructor( x : any) {
        if(typeof x === "string"){
            prop = new implementationA(); // Error reported here. how do I achieve this? 
        }
    }
}

行错误 - prop = new implementationA() 属性“内容”的类型不兼容。 类型“字符串”不可分配给类型“T”。 'T' 可以用与 'string' 无关的任意类型实例化

在这种情况下使用泛型的正确方法是什么?如何有条件地设置具有myGenericInterface 类型的类属性。

【问题讨论】:

    标签: typescript typescript-generics


    【解决方案1】:

    通过class sample&lt;T&gt; {,您将T 绑定到某个未知类型,可能既不是string 也不是number。如果T 是例如number[](一个数组),那么prop 将是myGenericInterface&lt;number[]&gt; 类型的值,不能分配myGenericInterface&lt;string&gt; 类型的值。

    你能做的就是改成

    class sample {
        prop : myGenericInterface<string|number>;
    
        constructor( x : any) {
            if(typeof x === "string"){
                this.prop = new implementationA();  // Now works
            }
        }
    }
    

    Playground

    【讨论】:

      【解决方案2】:

      问题

      class sample&lt;T&gt; 是一个泛型类,其中this.prop 的类型取决于该实例的泛型类型参数T 的类型。

      通常会设置一个泛型类,以便从传递给构造函数的参数中推断出实例的T 类型。您的构造函数只有(x : any),因此T 的类型将始终为unknown,除非您通过调用new sample&lt;string&gt;("") 显式设置它。

      参数xany,所以可以调用new sample&lt;number&gt;("")。在这种情况下,Tnumber。但是typeof x === "string"true,所以您将设置this.prop,它必须是myGenericInterface&lt;number&gt;implementationA,即myGenericInterface&lt;string&gt;。所以希望你能明白为什么 Typescript 在这一行给你一个错误。


      平庸的解决方案

      我认为您想要做的是将x 设为T 类型并限制T 使其只能是stringnumber

      您可以这样做,但它不是 100% 类型安全的,因为它要求我们做出一个可能正确但我们不能保证的断言。当我们检查typeof x === "string" 时,会将x 的类型细化为string,但不会细化T 的类型,因为从技术上讲T 是联合string | number 或@ 987654352@ 是string 的子集。所以我们必须使用as来抑制Typescript错误。

      class sample<T extends string | number> {
          prop: myGenericInterface<T>;
      
          constructor(x: T) {
              if (typeof x === "string") {
                  // x is known to be string, but we don't know that T is string
                  this.prop = new implementationA() as myGenericInterface<T>
              } else {
                  this.prop = new implementationB() as myGenericInterface<T>
              }
          }
      }
      

      很好的解决方案

      如果我们自己创建实现myGenericInterface&lt;T&gt; 的对象,我们可以保证任何类型(不仅仅是string | number)的类型安全。如果我们将propX 设置为x,那么我们不需要知道或关心T 的实际类型是什么,因为我们知道x 可以分配给T,所以{propX: x} 可以分配给@ 987654364@.

      class sample<T> {
          prop: myGenericInterface<T>;
      
          constructor(x: T) {
              this.prop = {
                  propX: x,
              }
          }
      }
      

      您可以通过使用泛型类来实现myGenericInterface&lt;T&gt;,从而通过额外的步骤使用相同的方法。

      class GenericImplementation<T> implements myGenericInterface<T> {
          propX: T;
      
          constructor(value: T) {
              this.propX = value;
          }
      }
      
      class sample<T> {
          prop: myGenericInterface<T>;
      
          constructor(x: T) {
              this.prop = new GenericImplementation(x);
          }
      }
      

      Typescript Playground Link

      【讨论】:

      • 感谢您的详细解释!
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-05-14
      • 1970-01-01
      • 2021-12-06
      • 2018-09-15
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多