11

I need to add a member to an HTMLElement, in other words, I need to store data into an element. This is what I would like to achieve as if I am coding in ScriptSharp.

/** My method */
public DoIt(element: Element, obj: Object) {
  Literal("{0}.extended = {1}", element, obj); // This is not standard Typescript!
}

In my example ScriptSharp (a project to convert C# code into Javascript) provides a Script.Literal object that allows developers to write plain Javascript when a C# abstraction is not possible.

So that the Javascript output is:

// Probably Typescript will render it a bit differently, but basically
// this is what we get in the end...
var _doit = function(element, obj) {
  element.extended = obj;
};

How can I achieve this in Typescript? Or maybe I should handle this problem in a different way?

0

3 Answers 3

19

Any valid JavaScript is also valid TypeScript. This means that you can write literal JS in any place in your code.

var _doit = function(element, obj) {
  element.extended = obj;
};

This is valid JS and TS.

However, since you use TypeScript, you may also want to use static typing with your code. If you just add types to your code, it will compile correctly, but you'll get a semantic error:

var _doit = function(element:HTMLElement, obj) {
  element.extended = obj; // error: HTMLElement doesn't have property 'extended'
};

To prevent this error, you can notify the compiler that you intend to create a new property on HTMLElement:

interface HTMLElement {
  extended?: any;
}

Now the compiler knows that you have an (optional) property extended on HTMLElement and will compile without errors. You will also get code autocompletion on this property (and JSDoc if provided).

Sign up to request clarification or add additional context in comments.

10 Comments

@Andry: yes, interfaces in TypeScript are open-ended, their contents are combined.
This is amazing thing! Thanks, I like your approach because any is fine but with an extended interface we are still having a bit of consistency and we actually declare how we want to extend stuff :)
@zlumer: This is actually not quite true. Consider the following construction of JSON. This would work fine in Javascript but leads to problems when written in Typescript (Online TS)
@Tom {blah['key1']: blah['key2']} is NOT valid JS nor JSON. According to ES5 spec, only IdentifierName, StringLiteral or NumericLiteral are allowed in object initializers. Like this: { foo: "identifier", 1:"numeric", "str":"string" }
@zlumer thanks for clearing that up! Didn't have a look into the specs, my bad. The piece of code I remembered was a ruby hash, where this is possible. Got confused there and didn't double check.
|
2

This worked for me:

class Foo {
  public DoIt(element: Element, obj: Object) {
    var anyElement: any = element;
    anyElement.extended = obj;
  }
}

The problem (as you probably noticed) is that Element does not declare a property with the name extended, so TypeScript does its job and enforces the Element type. If you want to work around this, you can use the any type to do this.

1 Comment

Thanks a bunch! Works great for me! This answer put an abrupt stop to my endless hours of scouring the internet.
2

Or maybe I should handle this problem in a different way?

If you want to completely break out of the compiler checking just have a standard javascript file. Note that if you want to use this from typescript you will have to tell typescript about it (using ambient declarations).

Personal Advice: Just use TypeScript.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.