问题
I'm trying to create a TypeScript 1.0.2 (VS 2013 Update 2 RTM) definition file for the ASP.NET Ajax library, and I'm getting hung up on how to define the additional methods that MS Ajax adds to base JS types such as Array. I created a AspNetAjax.d.ts and a AspNetAjax-tests.ts file. When I attempt to use the "add" method in the test file, I get the compiler error that is listed below.
AspNetAjax.d.ts
interface Array<T> {
add(array: T[], item: T): void;
}
AspNetAjax-tests.ts
///<reference path="AspNetAjax.d.ts" />
var a: string[] = ['a', 'b', 'c', 'd'];
Array.add(a, 'e');
console.log(a.toString());
Error 1 The property 'add' does not exist on value of type '{ isArray(arg: any): boolean; prototype: any[]; (arrayLength?: number): any[]; (arrayLength: number): T[]; (...items: T[]): T[]; new(arrayLength?: number): any[]; new(arrayLength: number): T[]; new(...items: T[]): T[]; }'. c:\path\AspNetAjax-tests.ts 4 7 TypeScriptHTMLApp1
Other definitions from the same d.ts file are working in the tests file so I know that the reference is physically working. TypeScript also doesn't complain about the way I've declared the d.ts file (no red squiggles there).
I am aware of these other questions and I thought I was doing what they suggested, but it seems they're from late 2012/early 2013 so perhaps the way to do this has changed since then?
Extending Array in TypeScript
Adding a property to Array in Typescript
How can I add a static method to an existing type?
I need to code the d.ts so that the code in the .ts file will work. Any ideas?
回答1:
The code you've written adds an add
member to Array instances, not the built-in Array
object.
The Array
built-in object is defined in lib.d.ts near line 1134:
declare var Array: {
new (arrayLength?: number): any[];
new <T>(arrayLength: number): T[];
new <T>(...items: T[]): T[];
(arrayLength?: number): any[];
<T>(arrayLength: number): T[];
<T>(...items: T[]): T[];
isArray(arg: any): boolean;
prototype: Array<any>;
}
If you want to add a member to Array
, you can modify the declaration as it appears in lib.d.ts.
If you're thinking that messing with lib.d.ts seems like a bad idea, it's because you shouldn't modify the built-in objects. There's no way to be sure that you and someone else haven't both decided that you have a great idea for an Array.add
method that have completely different behavior.
回答2:
You can take advantage of the declaration merging logic in TypeScript to extend Array
as shown :
declare module Array{
export var add:Function;
}
var a: string[] = ['a', 'b', 'c', 'd'];
Array.add(a, 'e'); // Okay now
console.log(a.toString());
回答3:
Between @basarat and @Ryan-Cavanaugh's answers I was able to come up with a minimally-horrible-to-the-user solution that works with TypeScript 1.0, as long as one is willing to accept that modifying the built-in JS objects is generally bad idea so it's OK if supporting that in TypeScript is slightly awkward.
Assuming that I am defining the ASP.NET AJAX extensions on the built-in JS Array object:
- I will declare a module in the d.ts file called
AspNetAjaxExtensions
- I will create a non-exported interface inside that module declaration called
JavaScriptArray<T>
- I will create an exported interface inside that module declaration called
Array<T>
thatextends JavaScriptArray<T>
- I will copy all of the definitions for
Array
andArray<T>
from the lib.d.ts that ships with TypeScript into the newJavaScriptArray<T>
interface. - I can then proceed to model out only the extended functionality inside the new
Array<T>
interface.
This is somewhat anti-DRY for the d.ts author, but in reality these things very infrequently change and the stuff in JavaScriptArray<T>
that was copied from lib.d.ts is self-contained. Technically, a build step could even be created to dynamically fill-in this interface.
For the user, they have to change their code that calls the extended Array
object from this:
//will be an error in TypeScript 1.0
Array.add(x, 'thing');
to this:
//This works in TypeScript 1.0 after importing the above-described d.ts file.
(<AspNetAjaxExtensions.Array<string>>Array).add(x, 'thing');
Feasibly one could even Find+Replace Array.add(
with (<AspNetAjaxExtensions.Array<any>>Array).add(
.
They only need to do this whenever any of the extended methods on the built-in Array object are called (which will be called out by TypeScript syntax errors). Calls to normal Array methods will still use the "normal" definition in lib.d.ts.
Example new AspNetAjax.d.ts file:
declare module AspNetAjaxExtensions {
/** This interface definition was copied from lib.d.ts */
interface JavaScriptArray<T> {
new (arrayLength?: number): any[];
new <T>(arrayLength: number): T[];
/* -- Snip out many copied and pasted lines of code from lib.d.ts -- */
}
/** JavaScript Array object as extended by ASP.NET Ajax */
export interface Array<T> extends JavaScriptArray<T> {
/** Adds an element to the end of an Array object. This function is static and is invoked without creating an instance of the object.
http://msdn.microsoft.com/en-us/library/bb310854(v=vs.100).aspx
@param array The array to add the item to.
@param item The object to add to the array.
*/
add(array: T[], item: T): void;
/* -- etc... defining remaining extended methods -- */
}
}
来源:https://stackoverflow.com/questions/23636093/add-method-to-array-in-typescript-1-0