组合 class 和接口类型

Combined class and interface type

在 Javascript(在 WScript 或 HTA 下)中,我会编写以下模式:

var fso = new ActiveXObject('Scripting.FileSystemObject');
var ext = fso.GetExtensionName('C:\test.txt');    //returns 'txt'
var badResult = fso.NonExistentMethod();          //raises a runtime error

使用 TypeScript,我可以声明一个接口来防止此类错误:

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

但是,我想像这样初始化 fso 变量:

var fso = new Scripting.FileSystemObject();

并让类型系统自动推断 fso 的类型是接口 Scripting.FileSystemObject.

这可以做到吗?


1) 无法在接口中添加构造函数,因为接口只是对象的形状,而不是它的实现。


2) 我考虑创建一个内部接口,并使用 class 和构造函数扩展接口:

module Scripting {
    interface Internal {
        GetExtensionName(path: string): string;
        GetParentFolderName(path: string): string;
    }

    export class FileSystemObject extends Internal {
        constructor() {
            return new ActiveXObject('Scripting.FileSystemObject');
        }
    }
}

但是如果不调用接口没有的基类型构造函数,就不能将构造函数添加到扩展 class。


3) 我不能有一个declared class,因为构造函数仍然是一个实现,不能写成declared class,这是一个环境上下文。

deduce that the type of fso is the interface Scripting.FileSystemObject.Can this be done?

当然可以。只需声明一些在使用 new 调用时将 return 为正确类型的东西。即下面的export var FileSystemObject: { new (): FileSystemObject };

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

try it

UPDATE 要自己实现类似的功能,您可以这样做:

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