Typescript 基于参数枚举返回泛型类型的构造函数:TS2322

Typescript 基于参数枚举返回泛型类型的构造函数:TS2322,typescript,generics,Typescript,Generics,我正在编写类型检查构造函数。 我希望返回对象类型具有与param value完全相同的字段值,但另一个字段取决于该值 function testConstructor<T extends En>( val: T ): { field: T; [x: string]: any; } { switch (val) { case En.one: return { field: En.one, anotherField: 1

我正在编写类型检查构造函数。 我希望返回对象类型具有与param value完全相同的字段值,但另一个字段取决于该值

function testConstructor<T extends En>(
  val: T
): {
  field: T;
  [x: string]: any;
} {
  switch (val) {
    case En.one:
      return {
        field: En.one,
        anotherField: 1,
      };
    case En.two:
      return {
        field: En.two,
        someAnotherField: 2,
      };
    default:
      return {
        field: val,
      };
  }
}
为什么我总是遇到这个错误,我如何才能修复它? 为什么开关防护装置不工作


@Phu-Ngo解决方案后出现错误(此版本的代码更接近我的实际代码。)

  • 在第
    行返回obj1

  • 不是用一个构造函数解决,而是用构造函数和函数解决

    enum枚举{
    一=‘一’,
    二=‘二’,
    }
    类型1={
    字段:Enum.one的类型;
    另一个字段:数字;
    };
    类型2={
    字段:Enum.two的类型;
    someAnotherField:数字;
    };
    类型n=类型1 |类型2;
    类型ConstructorN=()=>Extract<
    TypeN,
    {
    字段:T;
    }
    >;
    类型构造函数={
    [T in Enum]:构造函数;
    };
    let构造函数:构造函数={
    [枚举一]:()=>{
    设obj:Type1={
    字段:Enum.one,
    另一个领域:1,
    };
    返回obj;
    },
    [Enum.two]:()=>{
    设obj:Type2={
    字段:Enum.two,
    其他领域:2,
    };
    返回obj;
    },
    };
    console.log(构造函数[Enum.one]())
    log(构造函数[Enum.two]())
    
    您的类型保护将
    val
    限制为
    En.one
    可以,但是返回值的
    字段
    字段仍然需要为
    T
    T
    En。其中一个
    En
    的不同子类型,因此会出现错误。使用
    val
    而不是
    En.one
    @Phu-Ngo,
    >使用val而不是En.one
    -对,它可以工作,谢谢!)在不修改函数体的情况下,是否有另一种解决方案,可能是以不同的方式声明参数和返回类型?@Phu Ngo,我完成了问题中与实际代码更接近的代码,我得到了另一个错误:(呃,这将是一个你只是使用并继续的例子,比如。我怀疑你会发现编译器可以在不进行重大重构的情况下验证你正在尝试做的事情的安全性。如果这符合你的需要,我可以写一个你为什么需要这样做的答案。让我知道。假设你需要保持显式
    Type1
    Type2
    引用,我可以这样说。问题是,您无法让编译器通过控制流分析(如
    switch
    /
    case
    )缩小类型参数
    t
    ,因此您不应该尝试这样做。
    TS2322: Type 'En.two' is not assignable to type 'T'. 'En.two' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'En'.
    
    enum Enum {
      one = 'one',
      two = 'two',
    }
    
    type Type1 = {
      field: typeof Enum.one;
      anotherField: number;
    };
    
    type Type2 = {
      field: typeof Enum.two;
      someAnotherField: number;
    };
    
    function testConstructor<T extends Enum>(
      val: T
    ): {
      field: T;
      [x: string]: any;
    } {
      switch (val) {
        case Enum.one:
          let obj1: Type1 = {
            field: val,
            anotherField: 1,
          };
          return obj1;
        case Enum.two:
          let obj2: Type2 = {
            field: val,
            someAnotherField: 1,
          }
          return obj2;
      }
      throw Error(`unknown value ${val}`);
    }
    
    TS2322: Type 'T' is not assignable to type 'Enum.one'.   Type 'Enum' is not assignable to type 'Enum.one'.
    
    TS2322: Type 'Type1' is not assignable to type '{ [x: string]: any; field: T; }'.   Types of property 'field' are incompatible.     Type 'Enum.one' is not assignable to type 'T'.       'Enum.one' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'Enum'.
    
    enum Enum {
      one = 'one',
      two = 'two',
    }
    
    type Type1 = {
      field: typeof Enum.one;
      anotherField: number;
    };
    
    type Type2 = {
      field: typeof Enum.two;
      someAnotherField: number;
    };
    
    type TypeN = Type1 | Type2;
    
    type ConstructorN<T> = () => Extract<
      TypeN,
      {
        field: T;
      }
    >;
    
    type Constructors = {
      [T in Enum]: ConstructorN<T>;
    };
    
    let constructors: Constructors = {
      [Enum.one]: () => {
        let obj: Type1 = {
          field: Enum.one,
          anotherField: 1,
        };
        return obj;
      },
      [Enum.two]: () => {
        let obj: Type2 = {
          field: Enum.two,
          someAnotherField: 2,
        };
        return obj;
      },
    };
    
    console.log(constructors[Enum.one]())
    console.log(constructors[Enum.two]())