Dapatkan kelas dari instance di TypeScript


Bagaimana cara mendapatkan kelas dari sebuah instance di TypeScript? Pertanyaan ini mirip dengan Mendapatkan nama kelas sebuah objek saat runtime di TypeScript tetapi saya tidak ingin mendapatkan nama kelasnya. Saya ingin mendapatkan kelas itu sendiri.

Apa yang saya butuhkan ini untuk? TypeScript tidak memiliki metode kelas, hanya metode statis. Tapi mereka tidak virtual. Untuk sepenuhnya menerjemahkan model mental saya ke dalam kode Js, saya perlu memiliki metode kelas virtual.

Ide saya adalah melakukan sesuatu seperti ini:

function classOf<T>(o: T) : any {
    return o.class; // How to write this???
}

class Foo {
    static tryMe() : string {
        return "foo";
    }

}

class Bar extends Foo {
    static tryMe() : string {
        return "bar";
    }

}

function testPolymorphClassMethod(instance : Foo) {
    console.log(classOf(instance).tryMe());
}

testPolymorphClassMethod(new Foo()); // Should print "foo"
testPolymorphClassMethod(new Bar()); // Should print "bar"

Setiap kali sebuah kelas konkret tersedia, saya bisa memanggil metode statisnya secara langsung. Jika hanya sebuah instance yang tersedia, saya ingin memanggil metode statis dari kelasnya, misalnya membuatnya menjadi virtual secara manual.

Masalahnya adalah saya tidak tahu bagaimana menulis fungsi classOf. Mungkin itu sama sekali tidak mungkin.

Saya juga sedang mencoba ini:

function classOf<T>(o: T) : typeof T {
    return typeof o;
}

Tapi itu menghasilkan kesalahan kompilasi:

"T hanya merujuk pada sebuah tipe, tetapi digunakan sebagai nilai di sini".

Saya tahu bahwa fungsi adalah objek kelas pertama di JavaScript (dan juga TypeScript). Tetapi kelas TypeScript mungkin tidak, dan kemudian mungkin akan mustahil untuk melakukan apa yang saya inginkan.

Apakah ada cara alternatif untuk ini yang tidak memerlukan pengetikan banyak kode untuk setiap dan setiap kelas turunan?

Hal terdekat yang bisa saya dapatkan adalah:

class Virtualizer {
    virtual(methodName: string) : any {
        return eval(this.constructor.name+"."+methodName);
    }
}

class Foo extends Virtualizer {
    static getMyName() : string {
        return "foo";
    }

    public test() : string {
        return this.virtual("getMyName")();
    }

}

class Bar extends Foo {
    static getMyName() : string {
        return "bar";
    }    
}

let foo = new Foo();
let bar = new Bar();

console.log(foo.test()); // Prints "foo"
console.log(bar.test()); // Prints "bar"

Tapi ini kehilangan semua informasi tipe, itu membutuhkan kelas dasar yang sama (atau pengulangan kode), dan saya tidak pernah bisa memanggil metode sebenarnya yang ingin saya panggil, hanya "virtualizer". Ini sangat canggung.

Saya bisa mengekstrak informasi terkait kelas ke dalam objek singleton yang terenkapsulasi, tetapi itu akan mengharuskan saya mengubah visibilitas banyak metode dari protected menjadi public. (Dan juga menghasilkan banyak referensi silang antara objek utama dan objek yang terenkapsulasi, yang juga sangat canggung.)

Jawaban #1

Anda dapat mengembalikan properti constructor dari o Anda

function classOf<T>(o: T): any {
    return o.constructor;
}

Lihat Demo

Artikel terkait