Skip to content

Property getters/setters 'lost' when accessed from interface #206

@tomblind

Description

@tomblind

Properties with custom getters/setters in typescript only work in lua if accessed from a variable with the classes type. If accessed from a variable with an interface that maps to the class, the lua tries to access the property directly instead of calling the getter/setter.

Example:

interface Foo
{
    prop: string;
}

class Bar
{
    private _prop = "BAR";
    public get prop() { return this._prop; }
    public set prop(value: string) { this._prop = value; }
}

let bar = new Bar();
print(bar.prop);

let foo: Foo = bar;
print(foo.prop);

Produces:

Bar = Bar or {}
Bar.__index = Bar
function Bar.new(construct, ...)
    local instance = setmetatable({}, Bar)
    instance._prop = "BAR"
    if construct and Bar.constructor then Bar.constructor(instance, ...) end
    return instance
end
function Bar.constructor(self)
end
function Bar.get__prop(self)
    return self._prop
end
function Bar.set__prop(self,value)
    self._prop = value;
end
local bar = Bar.new(true);
print(bar:get__prop()); --prints "BASE"
local foo = bar;
print(foo.prop); --prints nil

One possible solution would be to use a custom metatable for classes with properties like these:

Bar = Bar or {}
Bar__meta =
{
    getters =
    {
        prop = function(self)
            return self._prop
        end
    },
    setters =
    {
        prop = function(self, value)
            self._prop = value
        end
    },
    __index = function(self, key)
        local getter = Bar__meta.getters[key]
        if getter then
            return getter(self)
        end
        return rawget(self, key) or Bar[key]
    end,
    __newindex = function(self, key, value)
        local setter = Bar__meta.setters[key]
        if setter then
            setter(self, value)
        else
            rawset(self, key, value)
        end
    end
}
function Bar.new(construct, ...)
    local instance = setmetatable({}, Bar__meta)
    instance._prop = "BAR"
    if construct and Bar.constructor then Bar.constructor(instance, ...) end
    return instance
end
function Bar.constructor(self)
end
local bar = Bar.new(true);
print(bar.prop);
local foo = bar;
print(foo.prop);

BTW, sorry for all the bugs. I have a large lua project which would really benefit from static typing so I'm putting tstl through it's paces to see if it will work for what I need. :)

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions