为什么赢得的Typescript声明了一个未赋值的变量?

时间:2017-03-20 09:24:21

标签: typescript

Typescript使用未分配的变量world编译以下类:

class Hello {
  world: string;
}

到以下javascript ,不带变量world的声明:

var Hello = (function () {
    function Hello() {
    }
    return Hello;
}());

但是,如果您将变量分配给任何

class Hello {
  world: string = undefined;
}

然后包含变量的声明

var Hello = (function () {
    function Hello() {
        this.world = undefined;
    }
    return Hello;
}());

为什么在没有为world分配默认值的情况下赢得了new Hello().hasOwnProperty('world') 的声明?

例如以下代码:

false

第一种情况返回true,第二种情况返回{{1}}。我确实希望它是真的,因为我已经在Typescript中声明了它(虽然我没有给它赋值)。

我也无法为此找到编译器选项。我错过了什么吗?为什么Typescript会这样做?

1 个答案:

答案 0 :(得分:3)

打字稿只是添加"语法糖"在javascript之上,但最后它被编译为js并且取决于js中支持的内容。

如果您查看es6 classes,您会发现没有相应的方式来声明成员在打字稿中完成的方式,成员定义只发生在构造函数中。< / p>

因此,除非您为其分配值,否则无法添加成员 只有两个选择:

  1. 添加到原型
  2. 添加到实例
  3. 将方法添加到原型中,但仅将成员添加到构造函数中发生的实例。

    修改

    有几种方法可以解决这个问题,最直接的方法是手动将undefined分配给构造函数中的所有成员(如您所述),但这并不能很好地扩展..

    你可以&#34;自动化&#34;它有几种方式,其中一种方法是使用decorators。在您的情况下,虽然您需要使用两个装饰器,一个用于the class,另一个用于the members

    这里似乎有用的东西:

    type RegistryEntry = {
        property: string;
        defaultValue: any;
    }
    const Registry = new Map<string, RegistryEntry[]>();
    
    function AssignDefaultValues(target: any) {
        var original = target;
    
        function construct(constructor, args) {
            var c: any = function () {
                return constructor.apply(this, args);;
            }
    
            c.prototype = constructor.prototype;
            const instance = new c();
    
            const entries = Registry.get(original.name) || [];
    
            entries.forEach(entry => {
                instance[entry.property] = entry.defaultValue;
            });
    
            return instance;
        }
    
        var f: any = function (...args) {
            return construct(original, args);
        }
    
        f.prototype = original.prototype;
        return f;
    }
    
    function DeclareProperty(defaultValue: any = undefined) {
        return function (target: any, property: string) {
            const className = target.constructor.name;
            let entries: RegistryEntry[];
    
            if (Registry.has(className)) {
                entries = Registry.get(className);
            } else {
                entries = [];
                Registry.set(className, entries);
            }
    
            entries.push({
                property,
                defaultValue
            });
        }
    }
    
    @AssignDefaultValues
    class Hello {
        @DeclareProperty()
        world: string;
    }
    
    let hello = new Hello();
    console.log(hello.hasOwnProperty("world")); // true
    

    code in playground

    这是一个很长的解决方案,但它似乎正在完成这项工作。