TypeScript: метод Specify возвращает тип this - PullRequest
0 голосов
/ 25 мая 2020

Делаю свой mysql орм для проекта. У меня есть абстрактный класс «модели», который другие модели, которые я создаю, могут наследовать и иметь все их методы и свойства. Моя единственная проблема на данный момент заключается в том, что я хочу указать, что метод будет возвращать тип класса, который его расширяет. Вот код.

import db from '../db'

export default abstract class Model {
    protected static TableName: string
    protected static Columns: string[]

    protected constructor() {
        console.log('Constructing a model')
    }
                                               //Change Model here to like "type of this"
    public static async findByID(id: string): Promise<Model> {
        const query = `select ${this.columns} from ${db.name}.${this.TableName} where ${this.Columns[0]}='${id}'`

        return (await db.query(query) as Model[])[0] //Change Model here to like "type of this"
    }

    private static get columns(): string {
        return this.Columns.reduce((acc, cur, i, arr) => i !== arr.length - 1 ? acc + cur + ', ' : acc + cur, '')
    }
}

Я знаю о потенциальной инъекции sql. Спасибо!

Ответы [ 2 ]

1 голос
/ 26 мая 2020

Вы ищете "polymorphi c this for stati c members", а он в настоящее время не является частью языка TypeScript. Возникла проблема с GitHub по адресу microsoft / TypeScript # 5863 . Это давняя нерешенная проблема, и я не вижу явных признаков того, что она когда-либо будет реализована или когда. К счастью, в этой проблеме упоминаются некоторые обходные пути, которые могут вам подойти:


В методе stati c this относится к типу конструктора класса, а не к типу его экземпляра. Вместо использования типа polymorphi c this вы можете использовать общий c this параметр :

public static async findByID<T extends Model>(
    this: { prototype: T }, id: string
) {
    const thiz = this as any as typeof Model;
    const query = 
      `select ${thiz.columns} from ${db.name}.${thiz.TableName} where ${thiz.Columns[0]}='${id}'`
    return (await db.query(query) as T[])[0]
}

Здесь мы говорим, что для call findById(), вам нужно вызвать его как метод объекта со свойством prototype generi c type T. В TypeScript свойство prototype конструкторов классов имеет тип экземпляра класса (несмотря на то, что это технически не соответствует действительности во время выполнения), поэтому, если у вас есть class Foo extends Model {...}, то Foo.findById() приведет к тому, что T будет выведено как Foo. Таким образом, вы можете рассматривать T как тип экземпляра конструктора подкласса. И findById() возвращает значение типа Promise<T>.

Обратите внимание на то, что, когда вы используете параметр this, вы переопределяете предполагаемый неполиморфный тип c this, то есть typeof Model. И, к сожалению, нет возможности получить доступ к методам и свойствам protected из общего c this. Поэтому я работаю над этим, делая значение thiz внутри findById() идентичным значению this и вручную утверждая, что оно имеет typeof Model, чтобы вы могли получить доступ к columns(), Columns и TableName .


Давайте убедимся, что это работает:

class SubModel extends Model {
    submodelProp = "foo"
}
SubModel.findByID("hello").then(s => s.submodelProp.toUpperCase())

Мне нравится ... SubModel.findById() возвращает Promise<SubModel>, о чем свидетельствует тот факт, что вы можете получить доступ его свойство submodelProp.


Хорошо, надеюсь, что это поможет; удачи!

Детская площадка ссылка на код

0 голосов
/ 25 мая 2020

Это невозможно в текущей версии TS 3.9, вы должны указать имя класса как есть: Model.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...