You just realized that prop1
has the incorrect type. It should actually be defined like this:
class A {
static prop1: typeof Hey;
⋯
}
The type Hey
refers to the instance type of the class Hey
, while typeof Hey
refers to the type of the constructor value of Hey
. Since static properties exist on the constructor, not on instances, prop1
should be of type typeof Hey
, not Hey
.
This distinction between types and values in TypeScript can be confusing because they exist in separate namespaces. Therefore, having a value named X
and a type named X
doesn’t necessarily mean they are related. This means that typeof X
is generally different from X
, requiring careful consideration. Check out this answer to a similar question for more details.
Once you make this correction, everything should work smoothly:
A.setFields()
console.log(A.prop1.a); // works fine
Keep in mind that the issue was somewhat hidden due to your Hey
class not having any instance members. An instance of Hey
is essentially identical in the type system to the empty object type {}
, allowing almost anything to be assigned to it. You may want to avoid using empty classes as they behave strangely in TypeScript. If a class exists, it should ideally have instance members. If Hey
had even one random property, you would have encountered this error:
class Hey {
⋯
oops = 0; // actual property
}
class A {
static prop1: Hey;
static setFields() {
this.prop1 = Hey.setABC('aee', 'bee', 'cee'); // error!
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Property 'oops' is missing in type 'typeof Hey' but required in type 'Hey'.
return this
}
}
If you never plan on creating instances of your class, plain objects might provide the desired behavior instead. For example:
const Hey = {
a: "",
b: "",
c: "",
setABC(a: string, b: string, c: string) {
this.a = a
this.b = b
this.c = c
return this
}
}
const A = {
prop1: Hey,
setFields() {
this.prop1 = Hey.setABC('aee', 'bee', 'cee')
return this
}
}
A.setFields()
console.log(A.prop1.a); // okay
This setup behaves similarly to your previous code. One key difference is that I initialized your properties whereas you left them undefined. However, leaving properties uninitialized could lead to potential null/undefined errors. Although TypeScript has strict initialization checks for class instances with --strictPropertyInitialization
, this feature does not yet cover static members (requested at microsoft/TypeScript#27899).
You are not obligated to refactor away from classes, but TypeScript’s support for empty classes with only static members is limited, as you’ve experienced.
Check out the code in the Playground