【问题标题】:TypeScript: Specify method returns 'this' typeTypeScript:指定方法返回“this”类型
【发布时间】:2020-05-25 19:39:31
【问题描述】:

为一个项目制作我自己的 mysql orm。我有一个抽象的“模型”类,我制作的其他模型可以继承并拥有它们的所有方法和属性。目前我唯一的问题是我想指定一个方法将返回扩展它的类的类型。这是一些代码。

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 注入。 谢谢!

【问题讨论】:

    标签: typescript


    【解决方案1】:

    您正在寻找“用于静态成员的多态 this”,它目前不是 TypeScript 语言的一部分。在 microsoft/TypeScript#5863 有一个 GitHub 问题要求它。这是一个长期悬而未决的问题,我看不到任何明显的迹象表明它将实施或何时实施。幸运的是,该问题确实提到了一些可能对您来说足够的解决方法:


    在静态方法中,this 指的是类构造函数的类型,而不是其实例类型。除了使用多态 this 类型,您还可以使用泛型 this parameter

    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]
    }
    

    这里我们说,为了调用findById(),您需要将其作为具有泛型类型Tprototype 属性的对象的方法来调用。在 TypeScript 中,类构造函数的 prototype 属性具有类实例的类型(尽管在运行时这在技术上并不正确),所以如果你有 class Foo extends Model {...} 那么 Foo.findById() 将导致 T 被推断为 @987654336 @。所以你可以把T当作子类构造函数的实例类型。而findById() 返回一个Promise&lt;T&gt; 类型的值。

    请注意,一旦使用 this 参数,就会覆盖推断的非多态 this 类型,即 typeof Model。不幸的是,无法从通用this 访问protected 方法和属性。因此,我通过在findById() 中创建与this 值相同的thiz 值来解决这个问题,并手动断言它具有typeof Model,因此您可以访问columns()ColumnsTableName .


    让我们确保它有效:

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

    对我来说看起来不错...SubModel.findById() 返回一个Promise&lt;SubModel&gt;,您可以访问其submodelProp 属性就证明了这一点。


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

    Playground link to code

    【讨论】:

      【解决方案2】:

      在当前的 TS 3.9 中是不可能的,您应该按原样指定类名:Model

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-04-05
        • 1970-01-01
        • 1970-01-01
        • 2011-11-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多