Reputation: 43
Given is the following test class:
class Test {
private readonly testString = "hello";
private readonly testStringImplicit: string = "hello";
public constructor() {
this.testString = "world";
this.testStringImplicit = "world";
}
}
Currently, Typescript 2.8.2 (and even current 2.9.2) produces the following error for the first property testString
:
TS2322: Type "world" is not assignable to type "hello".
My Question: Is this a bug?
I guess not, but i don't understand, why the type of the readonly property can be the value of them.
Thank you for every helpful answer
Upvotes: 4
Views: 294
Reputation: 1073988
It's a bit confusing, but the type of your testString
isn't string
, it's "hello"
, the string literal type with the sequence of characters h
, e
, l
, l
, o
. Your testStringImplicit
is explicitly typed string
, so you can assign any string to it, but your testString
is only allowed to have that one string literal value.
It has that type because it's readonly
, and that's the string you initialized it with. If it weren't readonly
, the inferred type would be string
, but because it's readonly
, tsc
is assuming the initialization is the only place you're going to write to it, and so gives it the "best common type" for "hello"
, which is the string literal type.
As jcalz helpfully points out, this is intended behavior. The relevant bullet point from that link:
- The type inferred for a
const
variable orreadonly
property without a type annotation is the type of the initializer as-is.
whereas
- The type inferred for a
let
variable,var
variable, parameter, or non-readonly
property with an initializer and no type annotation is the widened literal type of the initializer.
The word "constructor" doesn't appear in that pull request's text, so this effect that you can't assign a different value to testString
in the constructor, even though you're allowed to by readonly
's rules, doesn't seem to be discussed there. It may be discussed elsewhere.
Upvotes: 5