Daniel Fisher (lennybacon.com)

SOA, DATA & THE WEB

Visual Studio Intellisense support for parameters in JavaScript

From the perspective of a .NET developer JavaScript lacks of intellisense. Of course, Visual Studio is capable of showing intellisense for defined objects and their members, but when it comes to parameters we face the untyped world.

Last year I did a project with a few developers who had to leave their beloved C# world and enter the JavaScript area. Their motivation declined from day to day. So I thought of how to provide them with what they were missing like water in the desert.

My approach is based on the facade pattern. It allows to instanciate objects of a type with

  • an instance of the same type, to acts as a wrapper to restore intellisense
  • a JSON object, to be able to load data from a server request into a domain object

Here is the code:

function Person(data) {
	/// <summary>Instantiates a new instance of a Person.
	/// <para>	1. An JSON object containing data.</para>
	/// <para>	2. A Person object.</para>
	/// </summary>
	/// <param name="data" type="object">
	/// An object.
	/// <para>containing data to initialize a person.</para>
	/// <para>- or -</para>
	/// <para>of type Person beeing returned by the facade 
	/// to activate intellisense.</para>
	/// </param>
	var args, arg, member, lcMember, memberValue;
	this.firstName = '';

	this.lastName = '';

	this.fullName = function () {
		/// <summary>
		/// Returns the full name of the person.
		/// </summary>
		return this.firstName + ' ' + this.lastName;
	};

	//#region Facade pattern to keep intellisense alive...
	if (arguments !== null || arguments.length === 1) {
		args = arguments;
		arg = args[0];
		if (arg instanceof Person) {
			return arg;
		} else if (arg instanceof Object) {
			for (member in arg) {
				lcMember = 
					member.substring(0,1).toLowerCase() + 
					member.substring(1);
				if (this.hasOwnProperty(lcMember)) {
					memberValue = arg[lcMember];
					if (arg.hasOwnProperty(lcMember)) {
						memberValue = arg[lcMember];
					} else if (arg.hasOwnProperty(member)) {
						memberValue = arg[member]; 
					}
					if (typeof(memberValue) === 'string' &&
						memberValue.indexOf('/Date(') === 0) {
						memberValue =
							new Date(
							    parseInt(
								    memberValue.substr(6)));
					}
					this[lcMember] = memberValue;
				}
			}
		}
	}
	//#endregion
	
	return this;
}

The only thing I don’t like about is the fact that I need to name the type when comparing by instanceOf… Wrapped in an Visual Studio snippet eases up the pain…

image

And here is an example of the usage:

$(document).ready(
	function () {
		// After an object is instantiated intellisense works...
		var person = 
		    new Person({ 
			    firstName: 'daniel', 
				lastName: 'fisher' 
			});

		// ... but when passed as a parameter it gets lost ...
		printFullName(person);
	});

function printFullName(person) {
	// ... using the facade pattern we let intellisense 
	//        know what *type* it is.
	var thePerson = new Person(person);
	console.log(thePerson.fullName());
}

I hope this helps!

Comments

Write a comment