For object literals without type annotations, many TypeScript features don't work. Contrived example:
type User = { name: string; age: number };
const makeUser = () => ({ name: 'bob', age: 123 });
If you try to rename a property inside of the object literal (or vice versa, the property inside the type definition), it won't update the name of the corresponding property in the User
type definition. This is because TypeScript does not understand that this object literal relates to the User
type.
For the same reason, other language server features like "go to definition" and "find references" on object properties will also not work.
When a type is used in many places, this makes navigation and refactoring of the code much more difficult.
Furthermore, this can result in bugs:
type Config = { foo: string; bar?: string };
const config = { foo: 'yay', bar: 'woo' };
If we rename bar
in the Config
type, not only are the usages not automatically renamed but also we don't get a type error to say that we're now setting an invalid property in config
. In this situation it's likely we won't realise there is a problem, and this would probably cause a bug:
type Config = { foo: string; barNEW?: string };
// ❌ No type error!
const config = { foo: 'yay', bar: 'woo' };
Another example:
type State = { foo: string; bar: string };
declare const state: State;
const newState = { ...state, bar: 'woo' };
Rename bar
in the State
type and we get:
type State = { foo: string; barNEW: string };
declare const state: State;
// ❌ No type error!
const newState = { ...state, bar: 'woo' };
VS Code makes it easy to identify when TypeScript understands the relationship between a value and its type because it will highlight all occurrences of a symbol when that symbol is selected:
All occurences of myString
are highlighted:
Only one occurence of name
is highlighted: