Joshua Frank Joshua Frank - 2 months ago 11
TypeScript Question

Why doesn't Typescript Intellisense show Object extensions?

Consider this code to extend the Object type:

interface Object
{
doSomething() : void;
}

Object.prototype.doSomething = function ()
{
//do something
}


With this in place, the following both compile:

(this as Object).doSomething();
this.doSomething();


BUT: when I'm typing the first line, Intellisense knows about the
doSomething
method and shows it in the auto-completion list. When I'm typing the second line, it does not.

I'm puzzled about this, because doesn't every variable derive from Object, and therefore why doesn't Visual Studio show the extra method in the method list?

Update:



Even though the Intellisense doesn't offer the method, it does seem to recognize it when I've typed it manually:

enter image description here

What could explain that?!

Answer

...because doesn't every variable derive from Object

No, for two reasons:

1. JavaScript (and TypeScript) has both objects and primitives. this can hold any value (in strict mode), and consequently can be a primitive:

"use strict";
foo();
foo.call(42);

function foo() {
  console.log(typeof this);
}

Here's that same code in the TypeScript playground. In both cases (here and there), the above outputs:

undefined
number

...neither of which is derived from Object.

2. Not all objects inherit from Object.prototype:

var obj = Object.create(null);
console.log(typeof obj.toString); // undefined
console.log("toString" in obj);   // false

If an object's prototype chain is rooted in an object that doesn't have a prototype at all (like obj above), it won't have the features of Object.prototype.


From your comment below:

I thought even primitives like number inherit from Object. If number doesn't, how does number.ToString() work?

Primitives are primitives, which don't inherit from Object. But you're right that most of them seem to, because number, string, boolean, and symbol have object counterparts (Number, String, Boolean, and Symbol) which do derive from Object. But not all primitives do: undefined and null throw a TypeError if you try to treat them like objects. (Yes, null is a primitive even though typeof null is "object".)

For the four of them that have object counterparts, when you use a primitive like an object like this:

var a = 42;
console.log(a.toString());

...an appropriate type of object is created and initialized from the primitive via the abstract ToObject operation in the spec, and the resulting object's method is called; then unless that method returns that object reference (I don't think any built-in method does, but you can add one that does), the temporary object is immediately eligible for garbage collection. (Naturally, JavaScript engines optimize this process in common cases like toString and valueOf.)

You can tell the object is temporary by doing something like this:

var a = 42;
console.log(a);         // 42
console.log(typeof a);  // "number"
a.foo = "bar";          // temp object created and released
console.log(a.foo);     // undefined, the object wasn't assigned back to `a`

var b = new Number(42);
console.log(b);         // (See below)
console.log(typeof b);  // "object"
b.foo = "bar";          // since `b` refers to an object, the property...
console.log(b.foo);     // ... is retained: "bar"

(Re "see below": In the Stack Snippets console, you see {} there; in Chrome's real console, what you see depends on whether you have the console open: If you don't, opening it later will show you 42; if you do, you'll see ▶ Number {[[PrimitiveValue]]: 42} which you can expand with the ▶.)

Does number implement its own toString method, having nothing to do with Object?

Yes, but that doesn't really matter re your point about primitives and their odd relationship with Object.

So to round up:

  • this may contain a primitive, and while some primitives can be treated like objects, not all can.
  • this may contain an object reference for an object that doesn't derive from Object (which is to say, doesn't have Object.prototype in its prototype chain).

JavaScript is a hard language for IntelliSense. :-)