通过装饰器,如何使Typescript识别出我确实实现了抽象方法?

我有一个基本模型类,如下所示:

class Base {
    abstract public save(): Promise<Base>;
}

我的模型继承自Base,并且必须实现save方法。例如,

class User extends Base {
    public save(): Promise<User> {
        // save my user in the database and return a promise like this...
        return getDatabaseConnection()
            .then((db) => db.insert(...))
            .then((res) => this);
    }
}

这很好用,并且Typescript在这里的类型没有问题。

但是随着我的发展,我注意到我的模型save方法非常相似...

class Group extends Base {
    public save(): Promise<Group> {
        // save my group in the database and return a promise like this...
        return getDatabaseConnection()
            .then((db) => db.insert(...))
            .then((res) => this);
    }
}

class OtherModel extends Base {
    public save(): Promise<OtherModel> {
        // save my other model in the database and return a promise like this...
        return getDatabaseConnection()
            .then((db) => db.insert(...))
            .then((res) => this);
    }
}

因此我想到,为了使事情保持干燥,我可以实现一个装饰器,以将save方法添加到类中。

const save = (table: string,idColumn: string) => {
    return function decorator<T extends {new(...args: any[]): {}}>(target: T): T {
        return class extends target {
            public save = function() {
                // save whatever model this is & return it
                return getDatabaseConnection()
                    .then((db) => db.insert(...use the table,idColumn args...))
                    .then((res) => this);
            };
        }
    };
};

@save('user_table','id')
class User extends Base {}

@save('group_table','id')
class Group extends Base {}

@save('other_table','id')
class OtherModel extends Base {}

它的工作原理很吸引人,只是... Typescript抱怨类声明中缺少抽象方法save

我一直在使用@ts-ignore语句来解决它,但是我想删除它们。

我碰到了this question,它是关于通过装饰器添加到类中的 new 方法的,而且我知道装饰器无意修改接口或协定,但这不是事实。我在这里我正在尝试实现每个接口都存在(并且必须实现)的抽象方法。

如何通过装饰器让Typescript识别出我确实实现了抽象方法?

taikongman19992289 回答:通过装饰器,如何使Typescript识别出我确实实现了抽象方法?

我认为您所提问题的答案是,您应该在所有子类的save()方法上使用definite assignment assertion,这告诉编译器该方法已经实现,即使它可以不验证这一点。像这样:

@save('user_table','id')
class User extends Base {
    save!: () => Promise<this>;
}

@save('group_table','id')
class Group extends Base {
    save!: () => Promise<this>;
}

@save('other_table','id')
class OtherModel extends Base {
    save!: () => Promise<this>;
}

这将消除错误,尽管它有点重复并且需要比我期望的更多的手动注释。


这里的另一种方法可能是使用类工厂而不是装饰器。您可以上extend any expression that evaluates to a class constructor类。这与您对装饰器所做的操作没有太大不同。首先,我们制造工厂:

const Save = (table: string,idColumn: string) => class extends Base {
    public save() {
        // save whatever model this is & return it
        return Promise.resolve(this);
    }
};

只要适用于save(),就可以使用上面的Base方法实现。与装饰器的区别在于,对Save的调用直接返回扩展了Base的类,而不是返回扩展传递给它的类构造函数的函数。然后您的子类变为:

class User extends Save('user_table','id') {

}

class Group extends Save('group_table','id') {

}

class OtherModel extends Save('other_table','id') {

}

这些自动被视为Base的适当子类,因此没有任何地方值得担心。


好的,希望能有所帮助;祝你好运!

Link to code

本文链接:https://www.f2er.com/2973804.html

大家都在问