Headshot of Marius Schulz
Marius Schulz Front End Engineer

TypeScript 2.2: Dotted Properties and String Index Signatures

Before TypeScript 2.2, you were forced to use the [] notation if you wanted to access arbitrary properties of a type with a string index signature. You were not allowed to use the common . notation:

interface Dictionary<T> {
  [key: string]: T;
}

const portNumbers: Dictionary<number> = {};

// OK
portNumbers["http"] = 80;

// Error: Property 'http' does not exist on type 'Dictionary<number>'.
portNumbers.http = 80;

TypeScript 2.2 removes that restriction. You can now access properties using either bracket or dot notation without the compiler yelling at you. In many situations, there'll no longer be a need for unpleasant workarounds like this:

// Awkward!
(portNumbers as any).http = 80;

Note that the type must define an explicit string index signature in order for dotted property access to be type-correct for arbitrary properties. TypeScript 2.2 will therefore still give you a compile-time error for the following code:

const portNumbers = {};

// OK
portNumbers["http"] = 80;

// Error: Property 'http' does not exist on type '{}'.
portNumbers.http = 80;

It makes a lot of sense if you think about it: If TypeScript didn't give you an error for this code, there would be no protection against misspelled property names. You'll use dot notation most of the time when you access properties in JavaScript, but you can always fall back to bracket notation as an escape hatch.

With this loosened restriction, TypeScript makes another JavaScript idiom more natural to work with. This is especially helpful if you're migrating an existing JavaScript code base to TypeScript. Given proper string index signatures, you'll get fewer type errors in these cases, and you'll no longer need to annotate dotted property accesses with type annotations just to make the compiler happy.

This post is part of the TypeScript Evolution series:

  1. TypeScript 2.0: Non-Nullable Types
  2. TypeScript 2.0: Control Flow Based Type Analysis
  3. TypeScript 2.0: Acquiring Type Declaration Files
  4. TypeScript 2.0: Read-Only Properties
  5. TypeScript 2.0: Tagged Union Types
  6. TypeScript 2.0: More Literal Types
  7. TypeScript 2.0: The never Type
  8. TypeScript 2.0: Built-In Type Declarations
  9. TypeScript 2.1: async/await for ES3/ES5
  10. TypeScript 2.1: External Helpers Library
  11. TypeScript 2.1: Object Rest and Spread
  12. TypeScript 2.1: keyof and Lookup Types
  13. TypeScript 2.1: Mapped Types
  14. TypeScript 2.1: Improved Inference for Literal Types
  15. TypeScript 2.1: Literal Type Widening
  16. TypeScript 2.1: Untyped Imports
  17. TypeScript 2.2: The object Type
  18. TypeScript 2.2: Dotted Properties and String Index Signatures
  19. TypeScript 2.2: Null-Checking for Expression Operands
  20. TypeScript 2.2: Mixin Classes
  21. TypeScript 2.3: Generic Parameter Defaults
  22. TypeScript 2.3: The --strict Compiler Option
  23. TypeScript 2.3: Type-Checking JavaScript Files with --checkJs
  24. TypeScript 2.3: Downlevel Iteration for ES3/ES5
  25. TypeScript 2.4: String Enums
  26. TypeScript 2.4: Weak Type Detection
  27. TypeScript 2.4: Spelling Correction
  28. TypeScript 2.4: Dynamic import() Expressions
  29. TypeScript 2.5: Optional catch Binding
  30. TypeScript 2.6: JSX Fragment Syntax
  31. TypeScript 2.7: Numeric Separators
  32. TypeScript 2.7: Strict Property Initialization
  33. TypeScript 2.8: Per-File JSX Factories
  34. TypeScript 2.8: Conditional Types
  35. TypeScript 2.8: Mapped Type Modifiers