【问题标题】:'Class' is referenced directly or indirectly in its own type annotation'Class' 在其自己的类型注释中被直接或间接引用
【发布时间】:2018-02-06 20:40:59
【问题描述】:

这是基本的 DI 模式:

class Foo {
  foo = 1;
}

class Bar {
  constructor(public Foo: typeof Foo) {
    const foo = new Foo();
  }
}

class Baz extends Foo {}
new Bar(Baz);

它给出了一个错误:

'Foo' 在它自己的类型注解中被直接或间接引用。

但它显然不是自引用的,因为public Foo 是属性名称,typeof Foo 是类型。

这里发生了什么?是预计将来会解决的 TypeScript 错误吗?有记录吗?

Foo 属性名称可以以某种方式保留在这里而不重命名吗?这样命名才有意义。


看来public Foo: Foo 不会产生类型问题,而Foo 指的是public AnotherFoo: Foo 中的原始Foo 接口:

class Bar {
  constructor(public Foo: Foo, public AnotherFoo: Foo) {
    const foo: Foo = AnotherFoo;
    foo.foo;
  }
}

typeof Foo指的是Foo参数类型而不是原来的Foo接口:

class Bar {
  constructor(public Foo: number, Quux: typeof Foo) {
    const quux: number = Quux; 
  }
}

【问题讨论】:

  • 你为什么要在类声明中推断类型定义?这是多余的。 TSlint 插件会给你一个冗余定义类型的例外:例如let variable1: boolean = true 是冗余的。对于 Classes,这是一个例外,因为您正在引用他的类型和参数。只需声明一个类型 _Foo = typeof Foo 并将其提供给您的类参考 - 编辑没有在下面看到答案。提香是对的
  • type _Foo 是一个很好的解决方法。但是这个类型定义怎么是多余的呢?如果我不指定public Foo 的类型,它将是any。我没有public Foo = initialValue 来推断类型。

标签: typescript dependency-injection


【解决方案1】:

问题在于构造函数内部Foo 将引用参数而不是类,因此您不能仅通过名称引用Foo。保持参数名称的最简单方法是声明类型别名:

class Foo {
    foo = 1;
}
type FooType = typeof Foo
class Bar {
    constructor(public Foo: FooType) {
    }
}

Foo : Foo 有效但 Foo: typeof Foo 无效的原因是在类型 : 之后需要一个类型注释。如果在搜索符号时注释是名称,则仅认为类型是有效的。

typeof 之后,需要具有类型的符号名称(类、局部变量、参数等)。因此,搜索必须包含参数并且Foo 参数在范围内,因此必须考虑。

编辑

@artem 提出了一个很好的观点,我没有在上面明确指出:

[此行为] 并非特定于构造函数。在typeof Foo 中,Foo 指的是范围内名为Foo 的最接近的值(非类型)。一旦你有了一个名为 Foo 的参数,它就在作用域中(你甚至可以将它用作默认值来初始化其他参数),并且它会隐藏任何命名的外部值。

【讨论】:

  • 您能否提供解释这部分的参考资料或其他权威机构的链接,Foo 将引用参数而不是类public Foo: Foo 按我最初的预期工作,并且 Foo 实例类型(不是我需要的,但不会导致错误),但是 `typeof Foo` 用作对 Foo 参数类型的引用,请参阅更新。
  • @estus 我添加了一个解释,我不确定我可以提供什么权威来源,我可以寻找typeof如何工作的解释,有帮助吗?
  • 我不确定它是否会,如果你指的是this chapter。我想这与 type queries 而不是特别是 typeof 有关。我对了解构造函数参数类型中到底发生了什么非常感兴趣。如果答案无法解决这个问题,我想我会提供赏金。无论如何,感谢您的帮助,FooType 是应该在这里完成的方式。
  • 它不是特定于构造函数的。在typeof Foo 中,Foo 指的是范围内名为Foo 的最接近的值(不是类型)。一旦你有了一个名为 Foo 的参数,它就在作用域中(你甚至可以将它用作默认值来初始化其他参数),它会隐藏任何名为 Foo 的外部值
猜你喜欢
  • 2019-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-08-20
  • 2020-10-03
  • 2020-01-22
  • 1970-01-01
  • 2016-06-03
  • 1970-01-01
相关资源
最近更新 更多