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

ความแตกต่างระหว่าง "declare class" กับ "interface" ใน TypeScript คืออะไร


ใน TypeScript เมื่อสร้างไฟล์ประกาศต้นฉบับ .d.ts แบบใดจึงเหมาะสมกว่าและเพราะเหตุใด?

declare class Example {
    public Method(): void; 
}

หรือ

interface Example {
    Method(): void;
}

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

คำตอบ #1

interface ใช้สำหรับเมื่อคุณต้องการอธิบายรูปแบบของอ็อบเจ็กต์เท่านั้น จะไม่มีการสร้างโค้ดใด ๆ สำหรับ interfaces เลย — พวกมันเป็นเพียงสิ่งที่อยู่ในระบบประเภทเท่านั้น คุณจะไม่เห็นความแตกต่างในการสร้างโค้ดของคลาสไม่ว่าจะมีหรือไม่มีข้อกำหนด implements

`declare class` ใช้เมื่อคุณต้องการอธิบาย คลาสที่มีอยู่แล้ว (โดยปกติจะเป็นคลาส TypeScript แต่ไม่เสมอไป) ที่จะมีอยู่ภายนอก (ตัวอย่างเช่น คุณมีไฟล์ .ts สองไฟล์ที่คอมไพล์เป็นไฟล์ .js สองไฟล์และทั้งสองรวมผ่าน `script` ในเว็บเพจ) หากคุณสืบทอดจาก `class` โดยใช้ `extends` (โดยไม่ว่าแบบฐานจะเป็น `declare class` หรือ `class` ธรรมดา) ตัวคอมไพเลอร์จะสร้างโค้ดทั้งหมดเพื่อเชื่อมต่อห่วงโซ่ prototype และสร้าง constructors ส่งต่อและอื่น ๆ

ถ้าคุณพยายามสืบทอดจาก declare class ที่ควรจะเป็นอินเทอร์เฟซ คุณจะพบข้อผิดพลาดในเวลารันเนื่องจากโค้ดที่ถูกสร้างนั้นจะอ้างอิงไปยังวัตถุที่ไม่มีการแสดงผลในเวลารัน

ในทางกลับกัน ถ้าคุณเพียงแค่ implement อินเทอร์เฟซที่ควรจะเป็น declare class คุณจะต้องทำการ implement สมาชิกทั้งหมดด้วยตัวเองและจะไม่ได้ใช้ประโยชน์จากการใช้โค้ดซ้ำจากคลาสฐานที่ควรจะเป็น และฟังก์ชันที่ตรวจสอบสายพันธุ์ของโปรโตไทป์ในเวลารันไทม์จะปฏิเสธวัตถุของคุณเนื่องจากไม่ได้เป็นอินสแตนซ์จริงของคลาสฐาน

ถ้าจะเจาะลึกทางเทคนิคจริง ๆ ถ้าคุณมีพื้นฐาน C++ คุณสามารถคิดโดยประมาณว่า interface เหมือนกับ typedef และ declare class เหมือนกับการประกาศ extern ของคอนสตรัคเตอร์ที่ขาดนิยามอย่างเคร่งครัดในยูนิตคอมไพล์นี้

จากมุมมองด้านการใช้งานล้วนๆ (การเขียนโค้ดเชิงกำกับ ไม่ใช่การเพิ่มชนิดใหม่) ความแตกต่างเพียงอย่างเดียวระหว่าง interface และ declare class คือคุณไม่สามารถ new interface ได้ อย่างไรก็ตาม หากคุณตั้งใจที่จะ extend/implement หนึ่งในชนิดเหล่านี้ใน class ใหม่ คุณจำเป็นต้องเลือกอย่างถูกต้องระหว่าง interface และ declare class อย่างแน่นอน มีเพียงหนึ่งในนั้นที่ใช้งานได้

สองกฎที่ช่วยคุณได้ดี:

  • ชื่อของชนิดตรงกับฟังก์ชันสร้าง (สิ่งที่เรียกใช้งานได้ด้วย new) ที่มีอยู่จริงในเวลารันไทม์หรือไม่ (เช่น Date มี แต่ JQueryStatic ไม่มี)? หาก ไม่ใช่ คุณแน่นอนว่าควรใช้ interface
  • ฉันกำลังจัดการกับคลาสที่คอมไพล์มาจากไฟล์ TypeScript อื่นหรือสิ่งที่คล้ายกันเพียงพอหรือไม่? หาก ใช่ ให้ใช้ declare class

คำตอบ #2

คุณสามารถใช้งานอินเทอร์เฟซได้:

class MyClass implements Example {
    Method() {

    }
}

ในขณะที่ไวยากรณ์ declare class ถูกออกแบบมาเพื่อใช้ในการเพิ่มคำนิยามชนิดสำหรับโค้ดภายนอกที่ไม่ได้เขียนด้วย TypeScript — ดังนั้นการใช้งานจริงจะอยู่ที่ "อื่น"

คำตอบ #3

ในคำง่ายๆ declare ถูกใช้ในไฟล์ .ts/d.ts เพื่อบอกกับคอมไพเลอร์ว่าเราควรคาดหวังว่าคำสำคัญที่เรากำลัง ประกาศ จะมีอยู่ในสภาพแวดล้อมนั้น แม้ว่ามันจะไม่ได้ถูกกำหนดในไฟล์ปัจจุบันก็ตาม ซึ่งจะช่วยให้เรามีความปลอดภัยด้านประเภทข้อมูลเมื่อใช้วัตถุที่ประกาศ เนื่องจากคอมไพเลอร์ของ Typescript จะทราบว่ามีคอมโพเนนต์อื่นอาจให้ตัวแปรนั้น

คำตอบ #4

ความแตกต่างระหว่าง declare และ interface ใน TS:

ประกาศ:

declare class Example {
    public Method(): void; 
}

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

อินเทอร์เฟซ:

interface Example {
    Method(): void;
}

Interface เป็นโครงสร้างเสมือนที่มีอยู่เฉพาะใน TypeScript คอมไพเลอร์ของ TypeScript ใช้มันเพื่อจุดประสงค์เดียวคือการตรวจสอบชนิด เมื่อโค้ดถูกคอมไพล์เป็น JavaScript โครงสร้างทั้งหมดนี้จะถูกลบออก คอมไพเลอร์ของ TypeScript ใช้ interfaces เพื่อตรวจสอบว่าอ็อบเจ็กต์มีโครงสร้างที่ถูกต้องหรือไม่

ตัวอย่างเช่นเมื่อเรามีอินเทอร์เฟซดังต่อไปนี้:

interface test {
  foo: number,
  bar: string,
}

วัตถุที่เรากำหนดซึ่งมีประเภทอินเทอร์เฟซนี้จะต้องตรงกับอินเทอร์เฟซอย่างแม่นยำ:

// perfect match has all the properties with the right types, TS compiler will not complain.
  const obj1: test = {   
    foo: 5,
    bar: 'hey',
  }

บทความที่เกี่ยวข้อง