ค้นหาเว็บไซต์

javascript - คืนตัวสร้างของประเภททั่วไปใน TypeScript


ฉันกำลังพยายามหาวิธีเขียนโค้ด TypeScript ที่ระบุว่าฟังก์ชันนั้นคืนค่า constructor ของประเภท generic มีตัวอย่างมากมายเกี่ยวกับวิธีการส่ง constructor ของประเภท generic แต่ไม่ใช่วิธีการคืนค่า

โปรดตรวจสอบตัวอย่างต่อไปนี้:

นี่คือส่วนหนึ่งของคลาสนามธรรม:

 getModel():  (new () => T) {
    throw new Error('Method not implemented.'); // Error because don't know how to fix it
}

เมื่ออยู่ในคลาสย่อย ฉันกำลังพยายามใช้งานมันแบบนี้:

getModel(): typeof User {
    return User;
}

ฉันมีข้อผิดพลาดดังต่อไปนี้:

Type '() => typeof User' is not assignable to type '() => new () => User'.

ฉันสามารถข้ามการนำไปใช้ในคลาสที่สืบทอดได้ถ้าฉันรู้วิธีระบุในคลาสนามธรรม

ดังนั้นคำถามคือ - จะระบุได้อย่างไรในระดับคลาสเชิงนามธรรมว่าฟังก์ชันจะคืนค่าคอนสตรัคเตอร์ของประเภทเจเนอริก และฉันสามารถข้ามการใช้งานของฟังก์ชันนี้ในคลาสลูกได้หรือไม่? หรือบางทีฉันระบุลายเซ็นการคืนค่าไม่ถูกต้องในระดับคลาสเชิงนามธรรม?

แก้ไข:

กรุณาตรวจสอบปัญหาที่แปลก Class A และ B แตกต่างกันเพียงการมีตัวสร้างแบบชัดเจน และใน RealA ไม่ทำงานแต่ RealB ทำงานได้เหมือนกันกับเมธอด getModel()

class A {
a = '';
constructor(a: string) {

}
}

class B {
    a = '';
    static test(): void {
        console.log('I do work');
    }
}

abstract class Base<T> {
    Prop: T;
    constructor(TCreator: { new (): T; }) {
        this.Prop = new TCreator();
    }

    getModel(): (new () => T) {
        throw new Error('Method not implemented.'); // Error because don't know how to fix it
    }
}

class RealA extends Base<A> {
    getModel(): typeof A { // doesn't work - compilation error
        return A;
    }
}

class RealB extends Base<B> {
    getModel(): typeof B { // works
        return B;
    }
}

var test = new RealA(A); // compile error
var test2 = new RealB(B)

สำหรับคลาส RealA เกิดข้อผิดพลาดเดียวกัน

() => typeof A' is not assignable to type '() => new () => A'

คำตอบ #1

ข้อผิดพลาดนี้เป็นสิ่งที่คาดไว้เนื่องจากตัวสร้างของคลาส A มีอาร์กิวเมนต์ที่จำเป็น คลาสนามธรรมจำกัดให้ตัวสร้างต้องไม่มีอาร์กิวเมนต์ (new() => T)

วิธีแก้ปัญหาแบบง่ายคือการลบคอนสตรัคเตอร์ของ A

ถ้าคุณต้องการที่จะสามารถส่งผ่านในคลาสที่มีคอนสตรัคเตอร์ซึ่งต้องการอาร์กิวเมนต์ คุณจะต้องเปลี่ยนคำจำกัดความของคลาสฐานเพื่อจับประเภทคอนสตรัคเตอร์ และให้ constructor รับอาร์กิวเมนต์ที่จำเป็นเหล่านั้น (โดยใช้ทูเพิลในพารามิเตอร์ที่เหลือ)

class A {
    a = '';
    constructor(a: string) {

    }
}

class B {
    a = '';
    static test(): void {
        console.log('I do work');
    }
}

type ArgumentTypes<T> = T extends new (...a: infer A) => any? A : [] 
abstract class Base<T extends new (...a: any[])=> any> {
    Prop: InstanceType<T>;
    constructor(TCreator: T, ...a: ArgumentTypes<T>) {
        this.Prop = new TCreator(...a);
    }

    getModel(): T {
        throw new Error('Method not implemented.'); // Error because don't know how to fix it
    }
}

class RealA extends Base<typeof A> {
    getModel(): typeof A { // doesn't work - compilation error
        return A;
    }
}

class RealB extends Base<typeof B> {
    getModel(): typeof B { // works
        return B;
    }
}

var test = new RealA(A, ""); // ok
var test2 = new RealB(B)