Quite commonly in JavaScript code bases you would initialize object literals in the following manner:
let foo = {};
foo.bar = 123;
foo.bas = "Hello World";
As soon as you move the code to TypeScript you will start to get Errors like the following:
let foo = {};
foo.bar = 123; // Error: Property 'bar' does not exist on type '{}'
foo.bas = "Hello World"; // Error: Property 'bas' does not exist on type '{}'
This is because from the state let foo = {}
, TypeScript infers the type of foo
(left hand side of initializing assignment) to be the type of the right hand side {}
(i.e. an object with no properties). So, it error if you try to assign to a property it doesn't know about.
The proper way to initialize an object in TypeScript is to do it in the assignment:
let foo = {
bar: 123,
bas: "Hello World",
};
This is also great for code review and code maintainability purposes.
The quick fix and middle ground lazy initialization patterns described below suffer from mistakenly forgetting to initialize a property.
If you have a large JavaScript code base that you are migrating to TypeScript the ideal fix might not be a viable solution for you. In that case you can carefully use a type assertion to silence the compiler:
let foo = {} as any;
foo.bar = 123;
foo.bas = "Hello World";
Of course using the any
assertion can be very bad as it sort of defeats the safety of TypeScript. The middle ground fix is to create an interface
to ensure
- Good Docs
- Safe assignment
This is shown below:
interface Foo {
bar: number
bas: string
}
let foo = {} as Foo;
foo.bar = 123;
foo.bas = "Hello World";
Here is a quick example that shows the fact that using the interface can save you:
interface Foo {
bar: number
bas: string
}
let foo = {} as Foo;
foo.bar = 123;
foo.bas = "Hello World";
// later in the codebase:
foo.bar = 'Hello Stranger'; // Error: You probably misspelled `bas` as `bar`, cannot assign string to number