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

Typescript - คาดหวังประเภทที่สืบทอดคลาส


ฉันต้องสร้างฟังก์ชันที่คาดว่าจะรับชนิดของคลาสใดก็ได้ที่สืบทอดมาจากคลาสเฉพาะอีกคลาสหนึ่ง (ชนิด ไม่ใช่อ็อบเจกต์)

Class A{}

foo(b: typeof 'extends A')

Class B extends A{}

Class C {}


foo(B) => working

foo(C) => not working

มันสามารถทำได้อย่างไร?

คำตอบ #1

ฉันคิดว่าคุณอาจสับสนเกี่ยวกับประเภท ใน foo(B) B ไม่ใช่ประเภท มันคือค่าตัวสร้าง ความสับสนนี้ค่อนข้างพบบ่อย น่าจะเป็นเพราะบางครั้งประเภทและค่าสามารถมีชื่อเดียวกันได้ เช่นเมื่อตอนที่คุณประกาศ class

อย่างไรก็ตาม ถ้าความต้องการของคุณคือ foo() ควรรับอะไรก็ตามที่เป็นตัวสร้างของอินสแตนซ์ A สิ่งต่อไปนี้ควรใช้ได้:

class A { a: string = "A" }

declare function foo(ctor: new (...args: any[]) => A): void;

class B extends A { b: string = "B" }

class C { c: string = "C" }

foo(A); // okay
foo(B); // okay
foo(C); // error

ประเภท new (...args: any[]) => A หมายถึง "คอนสตรัคเตอร์ใดก็ได้ที่สร้างอินสแตนซ์ของประเภท A" ดังนั้น foo(B) ทำงานได้เพราะ B เป็นคอนสตรัคเตอร์ที่สร้างอินสแตนซ์ของประเภท B ซึ่งเป็นซับไทป์ของ A ดังนั้น B จึงสามารถสร้างอินสแตนซ์ของ A ได้ และ foo(B) จึงใช้งานได้ แต่เนื่องจากประเภท C ไม่ใช่ซับไทป์ของ A การเรียก foo(C) จึงทำให้เกิดข้อผิดพลาด

ฉันไม่รู้ว่าคุณต้องการทำอะไรภายในการใช้งานของ foo() ถ้าคุณต้องการใช้ตัวสร้างที่ส่งเข้ามาจริง ๆ คุณก็น่าจะต้องคิดเกี่ยวกับสิ่งที่อาร์กิวเมนต์ของตัวสร้างจำเป็นต้องเป็น และจำกัด foo() ให้ยอมรับเฉพาะตัวสร้างที่รองรับอาร์กิวเมนต์เหล่านั้น ตัวอย่างเช่น ถ้าคุณคาดหวังให้ foo() เรียกตัวสร้างโดยไม่มีอาร์กิวเมนต์ คุณก็น่าจะจำกัดมัน:

class A { a: string = "A" }

class B extends A { b: string = "B" }

class C { c: string = "C" }

// D's constructor requires a string argument
class D extends A { constructor(private d: string) { super(); } }

// ctor must be a no-arg constructor
declare function foo(ctor: new () => A): void;

foo(A); // still okay
foo(B); // still okay
foo(C); // still error
foo(D); // error

โปรดทราบด้วยว่าการมีคลาสว่าง ๆ เช่น class E {} ไม่แนะนำ แม้แต่สำหรับโค้ดตัวอย่าง เพราะระบบประเภทของ TypeScript อิงจากโครงสร้าง ไม่ใช่ชื่อ เนื่องจาก class A {} และ class C {} มีโครงสร้างเดียวกัน (ว่าง) ถ้าฉันเก็บประเภทเหล่านั้นไว้ การเรียก foo(C) จะไม่เกิดข้อผิดพลาด เมื่อสงสัยให้เพิ่มคุณสมบัติที่แตกต่างกันไปยังประเภทที่คุณตั้งใจให้คอมไพเลอร์ปฏิบัติต่างกัน

โอเค หวังว่านี่จะช่วยได้ โชคดีนะ!