成员声明,​​可以是带参数的方法,也可以是属性

时间:2018-02-05 08:37:41

标签: typescript

如何为可以同时属性(不带参数)或方法(带参数)的成员建模?

可以从没有参数的Javascript调用WSH Enivronment属性:

var shell = new ActiveXObject('WScript.Shell');
var env = shell.Environment;

或者,作为带参数的属性,从Javascript看起来像一个方法调用:

var filteredEnv = shell.Environment('System');

两种情况都返回WshEnvironment的实例,这是一组环境变量。

但是,在作为没有任何参数的方法调用时会引发错误:

var env2 = shell.Environment();

我可以将它建模为属性,或者作为带参数的方法,但不能同时建模:

declare interface WshShell {
    // ...

    // Error: Duplicate identifier
    Environment: WshEnvironment;
    Environment(Type: 'System' | 'User' | 'Process' | 'Volatile'): WshEnvironment;

    // ...
}

Playground

我可以输入WshEnvironment & {(Type: 'System' | 'User' | 'Process' | 'Volatile'): WshEnvironment};然后将编译以下内容:

let x: WshShell;
console.log(x.Environment.Count);
console.log(x.Environment('Process').Count);

Playground

但是Typescript会推断出从x.Environment返回的对象上的调用签名来过滤值,而调用签名实际上返回一个值,其中参数作为变量名称:

let env = x.Environment;
// Typescript will type filteredEnv as WshEnvironment
// At runtime, filteredEnv will contain an empty string (unless there is an environment variable named 'Process')
let filteredEnv = env('Process');

1 个答案:

答案 0 :(得分:1)

您可以声明具有扩展WshEnvironment

的呼叫签名的接口
// Added for testing 
declare interface WshEnvironment{
    (name: 'OS'): string
}

declare interface WshEnvironmentWithInvoke extends WshEnvironment {
    (Type: 'System' | 'User' | 'Proces' | 'Volatile'): WshEnvironment;
}
declare interface WshShell {

    Environment: WshEnvironmentWithInvoke;

}

let shell: WshShell;
shell.Environment("System")("OS");
shell.Environment("OS");

修改

上述解决方案允许进行这样的调用:

let env = x.Environment;
let filteredEnv = env('System');

不幸的是,在Typescript中无法正确输入,基本上有一个属性在从对象中分配出来时会丢失一些属性。我会去优化常见的场景,这里似乎是你指定参数的版本,主要是因为文档中的这一行:

  

如果未提供strType,则Environment属性将根据操作系统返回不同的环境变量类型。

我会创建一个辅助函数来为演员提供一些上下文,而不是内联:

declare interface WshEnvironment{
    (name: 'OS'): string
}
declare interface WshShell {
    Environment (Type?: 'System' | 'User' | 'Proces' | 'Volatile'): WshEnvironment

}

function defaultEnvironment(shell: WshShell) :WshEnvironment {
    return shell.Environment as any;
}
var shell: WshShell = new ActiveXObject('WScript.Shell');

var s = defaultEnvironment(shell);
WScript.Echo(s("OS"));
WScript.Echo(shell.Environment('System')("OS"));