In Javascript (under WScript or HTA), I would write the following pattern:
var fso = new ActiveXObject('Scripting.FileSystemObject');
var ext = fso.GetExtensionName('C:\test.txt'); //returns 'txt'
var badResult = fso.NonExistentMethod(); //raises a runtime error
Using TypeScript, I can declare an interface which will prevent this sort of error:
module Scripting {
export interface FileSystemObject {
GetExtensionName(path: string): string,
GetParentFolderName(path: string): string
}
}
var fso: Scripting.FileSystemObject = new ActiveXObject('Scripting.FileSystemObject');
var ext = fso.GetExtensionName('C:\test.txt'); //ext is recognized as a string
//var badResult = fso.NonExistentMethod(); //will not compile
However, I would like to initialize the fso
variable like this:
var fso = new Scripting.FileSystemObject();
and have the type system automatically deduce that the type of fso
is the interface Scripting.FileSystemObject
.
Can this be done?
1) I can't add the constructor to the interface, because the interface is only the shape of the object, not its implementation.
2) I thought about creating an internal interface, and extending the interface with a class and a constructor:
module Scripting {
interface Internal {
GetExtensionName(path: string): string;
GetParentFolderName(path: string): string;
}
export class FileSystemObject extends Internal {
constructor() {
return new ActiveXObject('Scripting.FileSystemObject');
}
}
}
but constructors cannot be added to an extending class without a call to the base type constructor, which an interface does not have.
3) I cannot have a single declared
class, because the constructor is still an implementation and cannot be written into a declared
class, which is an ambient context.
deduce that the type of fso is the interface Scripting.FileSystemObject.Can this be done?
Sure. Just declare to have something which when called with new
will return the correct type. i.e. export var FileSystemObject: { new (): FileSystemObject };
below :
declare module Scripting {
export interface FileSystemObject {
GetExtensionName(path: string): string;
GetParentFolderName(path: string): string;
}
export var FileSystemObject: { new (): FileSystemObject };
}
var fso: Scripting.FileSystemObject = new Scripting.FileSystemObject();
var ext = fso.GetExtensionName('C:\test.txt'); //ext is recognized as a string
var badResult = fso.NonExistentMethod(); //will not compile
UPDATE To implement something like this yourself you can do:
module Scripting {
export interface FileSystemObject {
GetExtensionName(path: string): string;
GetParentFolderName(path: string): string;
}
export var FileSystemObject: { new (): FileSystemObject } = <any>function(){
return new ActiveXObject('Scripting.FileSystemObject');
};
}
var fso: Scripting.FileSystemObject = new Scripting.FileSystemObject();
var ext = fso.GetExtensionName('C:\test.txt'); //ext is recognized as a string
var badResult = fso.NonExistentMethod(); //will not compile