ความแตกต่างระหว่าง "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',
}
