If TypeScript is a strict superset of JavaScript, why is dot notation on an arbitrary object erroneous? I have JS code that I want to convert over to TS for better type safety, but all access using dot notation (eg, myObj.thing
) gives me the error Property 'thing' does not exist on type '{}'.
. It works properly when I use bracket notation (eg, myObj['thing']
).
To dynamically access an object's property: Use keyof typeof obj as the type of the dynamic key, e.g. type ObjectKey = keyof typeof obj; . Use bracket notation to access the object's property, e.g. obj[myVar] .
The question mark dot (?.) syntax is called optional chaining in TypeScript and is like using dot notation to access a nested property of an object, but instead of causing an error if the reference is nullish, it short-circuits returning undefined .
The dot notation is used mostly as it is easier to read and comprehend and also less verbose. The main difference between dot notation and bracket notation is that the bracket notation allows us to access object properties using variable.
Property accessors provide access to an object's properties by using the dot notation or the bracket notation.
I know you say this is odd, but this is one of the main reasons TypeScript exists. This error helps prevent accidentally setting or getting non-existent properties on an object.
Right now, as the compiler is telling you, the property bar
does not exist on x
because it has been implicitly typed to {}
when writing var x = {};
.
You can tell the compiler that x
has more than zero properties by explicitly defining the type:
var x: { foo?: string; bar?: string; } = {};
Now you can get or set x.foo
and x.bar
without the compiler complaining. In most cases, you would move this into an interface like so:
interface IFooBar { foo?: string; bar?: string; } var x: IFooBar = {}; x.foo = "asdf"; // ok x.test = "asdf"; // error, as it should be
Some people are recommending you cast to any
, but don't get lazy. You should make full use of the type system TypeScript provides. Doing so will most definitely save you time down the road as you maintain an application.
Because of the strongly-typed nature of Typescript Object, you can use "any" to make it untyped:
var x: any = {}; x.bar = "bar"; /// ok
If what's you need is to define type of literal properties
var x: { [index: string]: TypeA } = {};
then x["bar"]
can now only be instance of TypeA.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With