If I have the classes
class Foo {
type: "foo"
constructor(public id: number) {}
}
class Bar {
type: "bar"
constructor(public id: number) {}
}
type SomeUnion = Foo | Bar // (x : SomeUnion).type will have the type "foo" | "bar"
Constructing an instance of new Foo(1)
will yield { id: 1 }
at runtime, but I would like to get { id: 1, type: "foo" }
.
A simple solution is of course to type the string constant twice, by assigning it in the constructor for example with this.type = "class_name"
.
However, this is non-ideal since I need to type the same string constant twice. It's not a huge deal, but it's the kind of thing one could forget and lead to bugs.
Is there a way to auto-create a member of the object with the same value as the string literal?
Let's concentrate on this code:
class Foo {
type: "foo"
constructor(public id: number) {}
}
If the compiler option strictNullChecks
is false
, then type: "foo"
implicitly also allows setting type
to the values undefined
and null
. I hope the need to explicitly initialize the field to a value other than undefined
is obvious.
So let's move on with strictNullChecks
set to true
. In this case, the only value that can be assigned to type
is "foo"
. It looks like what you're hoping to have some way to get the compiler to perform the following reasoning:
type: "foo"
says the field namedtype
must be of type"foo"
. Therefore, only the value"foo"
can be assigned to it. Consequently, I should emit code to automatically initialize it to"foo"
because there's no other value that can be assigned to it.
The problem is that TypeScript 2.x even with strictNullChecks
currently allows fields to start with the value undefined
even if assigning undefined
is not valid. Let me put this explicitly: even though you cannot assign the value undefined
to type
, the field type
can start with the value undefined
(if you do not initialize it). This is not deemed an error. This is how TypeScript is currently designed. There is an issue report about this, with some people arguing it is a design flaw in the language.
At any rate, the compiler does not perform the desired reasoning above. For now, one way or another, you will have to repeat the same value as part of the string literal type and as part of the initialization of your type
fields.
I think this will do what you are looking to do. You still have to type out the string literal twice, but they are typed out in close proximity, so you would be less likely to forget if the class type ever changes to update both values.
class Foo {
type: "foo" = "foo"
constructor(public id: number) {}
}
class Bar {
type: "bar" = "bar"
constructor(public id: number) {}
}
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