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']
).

- 1,572
- 2
- 16
- 33
-
4That's a warning, it should still compile, so TypeScript is still a strict superset of JS. The reason it is warning you is because TypeScript is typed, and the type of `x` does not specify `bar` properties. You can either cast to `any`, apply an interface that does have `bar`, or use `["bar"]`. – Asad Saeeduddin May 07 '15 at 00:28
-
@Asad: The error shown & described is reported as an error proper, not a warning, and my build fails. However, I am able to cast to `any` successfully. – user655321 May 07 '15 at 00:37
-
TypeScript is intentionally more strict that JavaScript, so having it be legal in Javascript does not necessarily mean the TypeScript compiler will agree. – Jared Farrish May 07 '15 at 12:21
5 Answers
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.

- 101,669
- 28
- 188
- 178
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.

- 21,938
- 10
- 68
- 86
x
does not hold any property named bar
so you need create it within the object:
function foobar() {
var x = {
foo: 'foo',
bar: 'bar'
}
return x;
}
alert(foobar().bar); //returns bar

- 12,295
- 7
- 55
- 95
-
1It's [apparently legal JS](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Working_with_Objects) to assign to a property that doesn't exist yet in an object, so it seems odd that I can't do it in TS without a cast to `any` (as @Asad describes above). – user655321 May 07 '15 at 00:37
-
Learning something new everyday... Multiple different ways to skin a cat, i guess. – mwilson May 07 '15 at 00:40
mwilson got there before I could! ;)
In the code above, Typescript is unable to determine that the object x
exposes a property called bar
so cannot resolve it when displaying Intellisense.
Instead, add foo
, bar
, etc. as properties of the object itself:
var x = {
foo: "FOO",
bar: "BAR"
};
Then, when using the Typescript Playground, you'll be see the Intellisense work as expected:
HTH

- 10,800
- 1
- 51
- 68
I personally prefer to specify types whenever I have the chance.
Note, that you can only instantiate this variable with {}
if you define the fields as optional with the ?:
operator.
let x: {foo?: string, bar?: string} = {};
x.foo = 'foo';
x.bar = 'bar';
As others have said, if you plan to use this type multiple times, it's probably better to make an explicit class for it.
PS: it's better to use let
instead of var
when programming in typescript. (e.g. the scope of a var
declaration is a bit quirky, compared to a let
which does what you expect it to do.)

- 22,839
- 10
- 110
- 123