Better inference for literal types

String, numeric and boolean literal types (e.g. "abc", 1, and true) were previously inferred only in the presence of an explicit type annotation.Starting with TypeScript 2.1, literal types are always inferred for const variables and readonly properties.

The type inferred for a const variable or readonly property without a type annotation is the type of the literal initializer.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.Where the widened type for a string literal type is string, number for numeric literal types, boolean for true or false and the containing enum for enum literal types.

Example
  1. const c1 = 1; // Type 1
  2. const c2 = c1; // Type 1
  3. const c3 = "abc"; // Type "abc"
  4. const c4 = true; // Type true
  5. const c5 = cond ? 1 : "abc"; // Type 1 | "abc"
  6. let v1 = 1; // Type number
  7. let v2 = c2; // Type number
  8. let v3 = c3; // Type string
  9. let v4 = c4; // Type boolean
  10. let v5 = c5; // Type number | string

Literal type widening can be controlled through explicit type annotations.Specifically, when an expression of a literal type is inferred for a const location without a type annotation, that const variable gets a widening literal type inferred.But when a const location has an explicit literal type annotation, the const variable gets a non-widening literal type.

Example
  1. const c1 = "hello"; // Widening type "hello"
  2. let v1 = c1; // Type string
  3. const c2: "hello" = "hello"; // Type "hello"
  4. let v2 = c2; // Type "hello"