TypeScript:泛型,它是任何普通对象

时间:2019-06-24 18:30:31

标签: typescript typescript-typings

  

编辑,这是我用来解释该问题的实际代码:

     

https://gist.github.com/LukasBombach/7bf255392074509147a250b448388518

使用TypeScript我想指定一个泛型,它是普通对象的任何数据结构

class MyClass<T extends {}> {
  public vars: T;

  constructor() {
    this.vars = {};
  }
}

所以我可以做

interface MyType {
  foo: string;
  bar: number;
}

new MyClass<MyType>()

interface MyType {
  baz: string;
  boo: {
    bam: Function;
    bix: number;
  };
}

new MyClass<MyType>()

我在那里建议的实现无法正常工作,但出现错误:

class MyClass<T extends {}> {
  public vars: T;

  constructor() {
    this.vars = {};
    //   ^^^^
  }
}
Type '{}' is not assignable to type 'T'.
  '{}' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint '{}'.ts(2322)

3 个答案:

答案 0 :(得分:1)

vars的类型定义为Partial<T>

class MyClass<T> {
  public vars: Partial<T>;

  constructor() {
    this.vars = {};
  }
}

这告诉TypeScript所有属性都是可选

const x = new MyClass<MyType>();

console.log(x.vars.foo); // prints "undefined" but there is no TS error
console.log(x.vars.thing); // prints "undefined" but TS error for unknown property.

https://netbasal.com/getting-to-know-the-partial-type-in-typescript-ecfcfbc87cb6

类型为 partial 时,始终为 partial 。您将收到以下警告。

const x: Partial<FooBar> = {};
const y: FooBar = x; // TS error, because x is partial.

您可以通过强制转换分配。

const y: FooBar = x as FooBar;

这里的事情是,您已经将变量定义为 partial 。因此, true 是您永远不会知道它是否真正填充了值。

您可以使用运行时类型验证程序来检查:

export function isMyType(value: any): value is MyType {
   return typeof value['foot'] === 'string'
          && typeof value['bar'] === 'number';
}

const x: Partial<MyType> = {};

if(isMyType(x)) {
    const y: MyType = x; // there is no TS, because of the isMyType check
}

我忘记了TypeScript中的is运算符被称为什么,但是当在条件块中使用时,用于检查变量的 type 发生了变化。因此TypeScript不会对此抱怨。

如果该值不是您认为的应有的值,它还可以引发运行时错误。

答案 1 :(得分:0)

错误完全符合逻辑。

使用您的第一个示例MyType,这等效于MyClass,没有通用名称:

interface MyType {
  foo: string;
  bar: number;
}

class MyClass {
  public vars: MyType;

  constructor() {
    this.vars = {};
  }
}

由于vars现在必须具有foobar成员,因此不允许分配vars = {}

答案 2 :(得分:0)

我认为这可能会解决

class MyClass<T extends {[key:string]: any}> {
  public vars: T;

  constructor() {
    this.vars = {};
  }
}

例如:

interface MyType {
  foo: string;
  bar: number;
}
let test = new MyClass<MyType>();

在测试中,您将能够找到MyType类型的var,而在test.vars中,您可以看到foo和bar属性可用