อะไรคือความแตกต่างระหว่างข้อความเหล่านี้ (ประเภทอินเตอร์เฟสเทียบกับ)?
interface X {
a: number
b: string
}
type X = {
a: number
b: string
};
อะไรคือความแตกต่างระหว่างข้อความเหล่านี้ (ประเภทอินเตอร์เฟสเทียบกับ)?
interface X {
a: number
b: string
}
type X = {
a: number
b: string
};
คำตอบ:
ซึ่งแตกต่างจากการประกาศอินเตอร์เฟสซึ่งมักจะแนะนำประเภทวัตถุที่มีชื่อการประกาศนามแฝงประเภทสามารถแนะนำชื่อสำหรับประเภทใด ๆ รวมทั้งดั้งเดิมสหภาพและประเภทแยก
สเปคไปพูดถึง:
ประเภทอินเตอร์เฟสมีความคล้ายคลึงกันหลายประการในการพิมพ์ชื่อแทนสำหรับตัวอักษรประเภทวัตถุ แต่เนื่องจากประเภทส่วนต่อประสานมีความสามารถมากขึ้น ตัวอย่างเช่นประเภทอินเตอร์เฟส
interface Point { x: number; y: number; }
สามารถเขียนเป็นนามแฝงประเภท
type Point = { x: number; y: number; };
อย่างไรก็ตามการทำเช่นนั้นหมายความว่าความสามารถต่อไปนี้จะสูญหายไป:
interface Point { x: number; } interface Point { y: number; }
extends or implements
ไม่ใช่กรณีอีกต่อไป class
ประเภทสามารถขยายและดำเนินการโดย นี่คือตัวอย่างtypescriptlang.org/play/…
คำตอบปัจจุบันและเอกสารอย่างเป็นทางการล้าสมัยแล้ว และสำหรับผู้ที่ยังใหม่กับ TypeScript คำศัพท์ที่ใช้ยังไม่ชัดเจนหากไม่มีตัวอย่าง ด้านล่างเป็นรายการความแตกต่างที่ทันสมัย
ทั้งสองสามารถใช้เพื่ออธิบายรูปร่างของวัตถุหรือลายเซ็นฟังก์ชัน แต่ไวยากรณ์แตกต่างกัน
อินเตอร์เฟซ
interface Point {
x: number;
y: number;
}
interface SetPoint {
(x: number, y: number): void;
}
พิมพ์นามแฝง
type Point = {
x: number;
y: number;
};
type SetPoint = (x: number, y: number) => void;
ซึ่งแตกต่างจากอินเตอร์เฟส, นามแฝงประเภทยังสามารถใช้สำหรับประเภทอื่น ๆ เช่น primitives, unions และ tuples
// primitive
type Name = string;
// object
type PartialPointX = { x: number; };
type PartialPointY = { y: number; };
// union
type PartialPoint = PartialPointX | PartialPointY;
// tuple
type Data = [number, string];
ทั้งสองสามารถขยายได้ แต่อีกครั้งไวยากรณ์แตกต่างกัน นอกจากนี้โปรดทราบว่าส่วนต่อประสานและประเภทนามแฝงนั้นไม่ได้เกิดขึ้นพร้อมกัน อินเทอร์เฟซสามารถขยายนามแฝงชนิดและในทางกลับกัน
อินเตอร์เฟสขยายอินเตอร์เฟส
interface PartialPointX { x: number; }
interface Point extends PartialPointX { y: number; }
ประเภทนามแฝงขยายนามแฝงประเภท
type PartialPointX = { x: number; };
type Point = PartialPointX & { y: number; };
อินเตอร์เฟสขยายนามแฝงประเภท
type PartialPointX = { x: number; };
interface Point extends PartialPointX { y: number; }
ประเภทนามแฝงขยายส่วนต่อประสาน
interface PartialPointX { x: number; }
type Point = PartialPointX & { y: number; };
คลาสสามารถนำอินเตอร์เฟสหรือนามแฝงประเภทไปใช้ได้ทั้งในแบบที่เหมือนกัน โปรดทราบว่าคลาสและอินเทอร์เฟซนั้นจะถือว่าเป็นพิมพ์เขียวแบบคงที่ ดังนั้นจึงไม่สามารถใช้ / ขยายนามแฝงประเภทที่ตั้งชื่อประเภทสหภาพ
interface Point {
x: number;
y: number;
}
class SomePoint implements Point {
x = 1;
y = 2;
}
type Point2 = {
x: number;
y: number;
};
class SomePoint2 implements Point2 {
x = 1;
y = 2;
}
type PartialPoint = { x: number; } | { y: number; };
// FIXME: can not implement a union type
class SomePartialPoint implements PartialPoint {
x = 1;
y = 2;
}
ไม่เหมือนกับนามแฝงประเภทอินเตอร์เฟสสามารถกำหนดได้หลายครั้งและจะถือว่าเป็นอินเทอร์เฟซเดียว (โดยมีสมาชิกของการประกาศทั้งหมดที่ถูกผสาน)
// These two declarations become:
// interface Point { x: number; y: number; }
interface Point { x: number; }
interface Point { y: number; }
const point: Point = { x: 1, y: 2 };
type
หรือinterface
? ฉันยังคงสับสนเมื่อฉันควรใช้อย่างใดอย่างหนึ่ง
type
กับข้อ จำกัด บางอย่าง (และข้อ จำกัด เหล่านี้ของ TypeScript 3.7 ก็หายไปเช่นกัน) การเชื่อมต่อสามารถขยายประเภท ชั้นเรียนสามารถใช้ประเภท ยิ่งกว่านั้นการนำเสนอข้อมูลเป็นภาพหน้าจอของตารางทำให้ผู้ที่มีปัญหาด้านการมองเห็นไม่สามารถเข้าถึงได้อย่างสมบูรณ์
https://www.typescriptlang.org/docs/handbook/advanced-types.html
สิ่งหนึ่งที่แตกต่างคืออินเตอร์เฟสสร้างชื่อใหม่ที่ใช้ทุกที่ ชื่อแทนประเภทไม่ได้สร้างชื่อใหม่ตัวอย่างเช่นข้อความแสดงข้อผิดพลาดจะไม่ใช้ชื่อแทน
// สร้างโครงสร้างแบบต้นไม้สำหรับวัตถุ คุณไม่สามารถทำสิ่งเดียวกันกับอินเทอร์เฟซได้เนื่องจากขาดการแยก (&)
type Tree<T> = T & { parent: Tree<T> };
// พิมพ์เพื่อ จำกัด ตัวแปรเพื่อกำหนดค่าเพียงไม่กี่ค่า อินเทอร์เฟซไม่มีสหภาพ (|)
type Choise = "A" | "B" | "C";
// ขอบคุณประเภทคุณสามารถประกาศประเภท nonNullable ได้เนื่องจากกลไกที่มีเงื่อนไข
type NonNullable<T> = T extends null | undefined ? never : T;
// คุณสามารถใช้ส่วนต่อประสานกับ OOP และใช้ 'ใช้' เพื่อกำหนดโครงกระดูกของวัตถุ / คลาส
interface IUser {
user: string;
password: string;
login: (user: string, password: string) => boolean;
}
class User implements IUser {
user = "user1"
password = "password1"
login(user: string, password: string) {
return (user == user && password == password)
}
}
// คุณสามารถขยายส่วนต่อประสานกับส่วนต่อประสานอื่นได้
interface IMyObject {
label: string,
}
interface IMyObjectWithSize extends IMyObject{
size?: number
}
นอกเหนือจากคำตอบที่ยอดเยี่ยมแล้วมีความแตกต่างที่เห็นได้ชัดเมื่อมันมาถึงการขยายประเภท vs อินเตอร์เฟซ ฉันเพิ่งพบกรณีที่อินเทอร์เฟซไม่สามารถทำงาน:
เอกสารอธิบายไว้
- สิ่งหนึ่งที่แตกต่างคืออินเตอร์เฟสสร้างชื่อใหม่ที่ใช้ทุกที่ นามแฝงประเภทจะไม่สร้างชื่อใหม่ตัวอย่างเช่นข้อความแสดงข้อผิดพลาดจะไม่ใช้ชื่อแทนใน TypeScript ที่เก่ากว่าชื่อแทนประเภทไม่สามารถขยายหรือนำไปใช้จาก (หรือพวกเขาไม่สามารถขยาย / ใช้ประเภทอื่น ๆ ) ในเวอร์ชัน 2.7, นามแฝงประเภทสามารถขยายได้โดยการสร้างประเภททางแยกใหม่
- ในทางกลับกันถ้าคุณไม่สามารถแสดงรูปร่างด้วยอินเทอร์เฟซและคุณต้องใช้การรวมแบบยูเนี่ยนหรือทูเปิลชื่อแทนประเภทมักจะเป็นวิธีที่จะไป