Here is basic DI pattern:
class Foo {
foo = 1;
}
class Bar {
constructor(public Foo: typeof Foo) {
const foo = new Foo();
}
}
class Baz extends Foo {}
new Bar(Baz);
It gives an error:
'Foo' is referenced directly or indirectly in its own type annotation.
But it clearly isn't self-referential, because public Foo
is property name, and typeof Foo
is type.
What is going on here? Is it TypeScript bug that is expected to be solved in future? Is it documented?
Can Foo
property name be kept somehow here without renaming it? It just makes sense to name it so.
It appears that public Foo: Foo
doesn't create problems with types, and Foo
refers to original Foo
interface in public AnotherFoo: Foo
:
class Bar {
constructor(public Foo: Foo, public AnotherFoo: Foo) {
const foo: Foo = AnotherFoo;
foo.foo;
}
}
And typeof Foo
refers to Foo
parameter type and not original Foo
interface:
class Bar {
constructor(public Foo: number, Quux: typeof Foo) {
const quux: number = Quux;
}
}
}), }); 'LocationType' implicitly has type 'any' because it does not have a type annotation and is referenced directly or indirectly in its own initializer. You just have to specify the LocationType type to GraphQLObjectType.
So key does indeed indirectly reference itself in its initializer… and this is pretty solidly "design limitation" territory. Of course, at many of these above bullet points, a reasonable human being may well differ in behavior from the compiler. For example, consider The type of current.x + ',' depends on the type of current.x and the type of ','
If the annotation is a name when searching for the symbol, only types are considered as only they can be valid. After typeof the name of a symbol that has a type is expected (class, local variable, parameter, etc.). So then the search must include parameters and the Foo parameter is in scope so it must be considered.
class Foo { foo = 1; } class Bar { constructor (public Foo: typeof Foo) { const foo = new Foo (); } } class Baz extends Foo {} new Bar (Baz); 'Foo' is referenced directly or indirectly in its own type annotation. But it clearly isn't self-referential, because public Foo is property name, and typeof Foo is type.
The problem is that inside the constructor Foo
will refer to the parameter not the class, so you can't reference Foo
by name alone. The simplest way to do it and keep the name of the parameter is to declare a type alias:
class Foo {
foo = 1;
}
type FooType = typeof Foo
class Bar {
constructor(public Foo: FooType) {
}
}
The reason Foo : Foo
works but Foo: typeof Foo
does not work is that after the type :
a type annotation is expected. If the annotation is a name when searching for the symbol, only types are considered as only they can be valid.
After typeof
the name of a symbol that has a type is expected (class, local variable, parameter, etc.). So then the search must include parameters and the Foo
parameter is in scope so it must be considered.
Edit
@artem makes a good point that I did not explicitly call out above:
[This behavior] is not specific to the constructors. In
typeof Foo
,Foo
refer to the nearest value (not type) namedFoo
in the scope. Once you have a parameter namedFoo
, it's in the scope (you can even use it as default value to initialize other parameters), and it shadows any outer values named.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With