代码之家  ›  专栏  ›  技术社区  ›  Zev Spitz

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

  •  1
  • Zev Spitz  · 技术社区  · 8 年前

    如何为既可以是属性(无参数)又可以是方法(有参数)的成员建模?

    WSH Enivronment 属性可以从Javascript调用,无需参数:

    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 回复  |  直到 8 年前
        1
  •  1
  •   Titian Cernicova-Dragomir    8 年前

    可以声明具有扩展的调用签名的接口 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属性将根据操作系统返回不同的环境变量类型。

    我希望创建一个helper函数来为cast提供一些上下文,而不是内联执行:

    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"));
    
    推荐文章