TypeScript: การเชื่อมต่อกับประเภท


715

อะไรคือความแตกต่างระหว่างข้อความเหล่านี้ (ประเภทอินเตอร์เฟสเทียบกับ)?

interface X {
    a: number
    b: string
}

type X = {
    a: number
    b: string
};

4
พบบทความนี้อธิบายความแตกต่าง - medium.com/@martin_hotell/…
Sandeep GB

คำตอบ:


573

ตามข้อกำหนดภาษา TypeScript :

ซึ่งแตกต่างจากการประกาศอินเตอร์เฟสซึ่งมักจะแนะนำประเภทวัตถุที่มีชื่อการประกาศนามแฝงประเภทสามารถแนะนำชื่อสำหรับประเภทใด ๆ รวมทั้งดั้งเดิมสหภาพและประเภทแยก

สเปคไปพูดถึง:

ประเภทอินเตอร์เฟสมีความคล้ายคลึงกันหลายประการในการพิมพ์ชื่อแทนสำหรับตัวอักษรประเภทวัตถุ แต่เนื่องจากประเภทส่วนต่อประสานมีความสามารถมากขึ้น ตัวอย่างเช่นประเภทอินเตอร์เฟส

interface Point {
    x: number;
    y: number;
}

สามารถเขียนเป็นนามแฝงประเภท

type Point = {
    x: number;
    y: number;
};

อย่างไรก็ตามการทำเช่นนั้นหมายความว่าความสามารถต่อไปนี้จะสูญหายไป:

  • อินเทอร์เฟซสามารถตั้งชื่อในส่วนขยายหรือส่วนคำสั่ง แต่นามแฝงชนิดสำหรับตัวอักษรชนิดของวัตถุไม่สามารถเป็นจริงได้อีกต่อไปตั้งแต่ TS 2.7
  • อินเทอร์เฟซสามารถมีการประกาศหลายผสานแต่นามแฝงชนิดสำหรับตัวอักษรชนิดของวัตถุไม่สามารถ

109
"การประกาศที่ผสานหลายอย่าง" หมายความว่าอะไรในข้อแตกต่างที่สอง?
jrahhali

66
@jrahhali ถ้าคุณกำหนดอินเตอร์เฟสสองครั้ง typescript จะรวมเข้าไปในที่เดียว
Andrey Fedorov

39
@jrahhali ถ้าคุณกำหนด type สองครั้ง typescript จะทำให้คุณมีข้อผิดพลาด
Andrey Fedorov

18
@jrahhaliinterface Point { x: number; } interface Point { y: number; }
Nahuel Greco

20
ฉันเชื่อว่าประเด็นแรกextends or implementsไม่ใช่กรณีอีกต่อไป classประเภทสามารถขยายและดำเนินการโดย นี่คือตัวอย่างtypescriptlang.org/play/…
dark_ruby

775

อัพเดต 2019


คำตอบปัจจุบันและเอกสารอย่างเป็นทางการล้าสมัยแล้ว และสำหรับผู้ที่ยังใหม่กับ TypeScript คำศัพท์ที่ใช้ยังไม่ชัดเจนหากไม่มีตัวอย่าง ด้านล่างเป็นรายการความแตกต่างที่ทันสมัย

1. วัตถุ / ฟังก์ชั่น

ทั้งสองสามารถใช้เพื่ออธิบายรูปร่างของวัตถุหรือลายเซ็นฟังก์ชัน แต่ไวยากรณ์แตกต่างกัน

อินเตอร์เฟซ

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;

2. ประเภทอื่น ๆ

ซึ่งแตกต่างจากอินเตอร์เฟส, นามแฝงประเภทยังสามารถใช้สำหรับประเภทอื่น ๆ เช่น 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];

3. ขยาย

ทั้งสองสามารถขยายได้ แต่อีกครั้งไวยากรณ์แตกต่างกัน นอกจากนี้โปรดทราบว่าส่วนต่อประสานและประเภทนามแฝงนั้นไม่ได้เกิดขึ้นพร้อมกัน อินเทอร์เฟซสามารถขยายนามแฝงชนิดและในทางกลับกัน

อินเตอร์เฟสขยายอินเตอร์เฟส

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; };

4. การดำเนินการ

คลาสสามารถนำอินเตอร์เฟสหรือนามแฝงประเภทไปใช้ได้ทั้งในแบบที่เหมือนกัน โปรดทราบว่าคลาสและอินเทอร์เฟซนั้นจะถือว่าเป็นพิมพ์เขียวแบบคงที่ ดังนั้นจึงไม่สามารถใช้ / ขยายนามแฝงประเภทที่ตั้งชื่อประเภทสหภาพ

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;
}

5. การประกาศการรวม

ไม่เหมือนกับนามแฝงประเภทอินเตอร์เฟสสามารถกำหนดได้หลายครั้งและจะถือว่าเป็นอินเทอร์เฟซเดียว (โดยมีสมาชิกของการประกาศทั้งหมดที่ถูกผสาน)

// 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 };

9
หากเอกสารอย่างเป็นทางการล้าสมัยข้อมูลที่คุณให้ไว้จะได้รับการยืนยันได้อย่างไร
iX3

59
จากการโพสต์นี้ดูเหมือนว่าเหตุผลเดียวที่เลือกอินเทอร์เฟซเหนือนามแฝงประเภทคือหากคุณต้องการใช้คุณสมบัติการรวมประกาศ (จุด 5) ของอินเทอร์เฟซ นอกเหนือจากนั้นพวกเขาจะเทียบเท่า (และฉันจะยืนยันว่านามแฝงประเภทที่เสนอไวยากรณ์ที่กระชับมากขึ้น)
maxedison

17
ฉันมักจะใช้อินเทอร์เฟซสำหรับวัตถุประเภทตัวอักษรมิฉะนั้นการใช้ประเภทที่เหมาะสมกว่าฉันคิดว่าการประกาศรวมไม่ควรใช้ในที่ใด ๆ จริง ๆ แล้วฉันจะไม่คาดหวังว่าอินเทอร์เฟซจะถูกประกาศในไฟล์อื่นของโครงการ คุณสมบัติพิเศษการตรวจสอบชนิดถูกสร้างขึ้นมาเพื่อทำให้ชีวิตของคุณง่ายขึ้นโดยไม่ทำให้ยากขึ้นด้วยอินเทอร์เฟซแบบนินจานี้: D
Ahmed Kamal

8
ดังนั้นโดยทั่วไปมันเป็นตัวเลือก "เกือบเป็นส่วนตัว" กับสิ่งที่เรารู้สึกสะดวกสบายในการใช้งานจริงหรือ นอกจากเหตุผลเดียวคุณสามารถใช้typeหรือinterface? ฉันยังคงสับสนเมื่อฉันควรใช้อย่างใดอย่างหนึ่ง
โจเซฟบริกส์

7
ใครช่วยกรุณาให้แรงจูงใจสำหรับเหตุผลที่คุณต้องการรวมอินเทอร์เฟซ ดูเหมือนว่าอาจทำให้ฉันสับสน ทำไมคุณต้องการกระจายคำจำกัดความของอินเทอร์เฟซของคุณข้ามบล็อกต่าง ๆ
Vanquish46

95

ตั้งแต่ TypeScript 3.2 (พ.ย. 2018) ข้อมูลต่อไปนี้เป็นจริง:

ป้อนคำอธิบายรูปภาพที่นี่


9
คุณช่วยกรุณาให้ข้อมูลเพิ่มเติมเกี่ยวกับวิธีสร้างตาราง / รูปภาพที่คุณให้ไว้? เช่นซอร์สโค้ดหรือลิงก์ไปยังเอกสาร
iX3

23
ใช่ฉันหมายถึงที่มาของเนื้อหาไม่ใช่งานนำเสนอ
iX3

3
ฉันไม่เชื่อว่าคลาสสามารถขยายประเภทหรืออินเทอร์เฟซได้และฉันไม่เห็นว่าทำไมคุณถึงต้องการ ??
Dan King

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

2
ตารางนี้ขาดแหล่งข้อมูลใด ๆ เพื่อสนับสนุนเนื้อหาและฉันจะไม่พึ่งพา ตัวอย่างเช่นคุณสามารถกำหนดชนิดเรียกซ้ำโดยใช้typeกับข้อ จำกัด บางอย่าง (และข้อ จำกัด เหล่านี้ของ TypeScript 3.7 ก็หายไปเช่นกัน) การเชื่อมต่อสามารถขยายประเภท ชั้นเรียนสามารถใช้ประเภท ยิ่งกว่านั้นการนำเสนอข้อมูลเป็นภาพหน้าจอของตารางทำให้ผู้ที่มีปัญหาด้านการมองเห็นไม่สามารถเข้าถึงได้อย่างสมบูรณ์
Michał Miszczyszyn

22

https://www.typescriptlang.org/docs/handbook/advanced-types.html

สิ่งหนึ่งที่แตกต่างคืออินเตอร์เฟสสร้างชื่อใหม่ที่ใช้ทุกที่ ชื่อแทนประเภทไม่ได้สร้างชื่อใหม่ตัวอย่างเช่นข้อความแสดงข้อผิดพลาดจะไม่ใช้ชื่อแทน


30
สิ่งนี้ล้าสมัยแล้วและไม่เป็นจริงอีกต่อไปตั้งแต่ TypeScript 2.1 ดู. medium.com/@martin_hotell/…
demisx

5

ตัวอย่างที่มีประเภท:

// สร้างโครงสร้างแบบต้นไม้สำหรับวัตถุ คุณไม่สามารถทำสิ่งเดียวกันกับอินเทอร์เฟซได้เนื่องจากขาดการแยก (&)

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
    }

1

นอกเหนือจากคำตอบที่ยอดเยี่ยมแล้วมีความแตกต่างที่เห็นได้ชัดเมื่อมันมาถึงการขยายประเภท vs อินเตอร์เฟซ ฉันเพิ่งพบกรณีที่อินเทอร์เฟซไม่สามารถทำงาน:

  1. ไม่สามารถขยายประเภทยูเนี่ยนโดยใช้อินเตอร์เฟส
  2. ไม่สามารถขยายส่วนต่อประสานทั่วไป

-2

เอกสารอธิบายไว้

  • สิ่งหนึ่งที่แตกต่างคืออินเตอร์เฟสสร้างชื่อใหม่ที่ใช้ทุกที่ นามแฝงประเภทจะไม่สร้างชื่อใหม่ตัวอย่างเช่นข้อความแสดงข้อผิดพลาดจะไม่ใช้ชื่อแทนใน TypeScript ที่เก่ากว่าชื่อแทนประเภทไม่สามารถขยายหรือนำไปใช้จาก (หรือพวกเขาไม่สามารถขยาย / ใช้ประเภทอื่น ๆ ) ในเวอร์ชัน 2.7, นามแฝงประเภทสามารถขยายได้โดยการสร้างประเภททางแยกใหม่
  • ในทางกลับกันถ้าคุณไม่สามารถแสดงรูปร่างด้วยอินเทอร์เฟซและคุณต้องใช้การรวมแบบยูเนี่ยนหรือทูเปิลชื่อแทนประเภทมักจะเป็นวิธีที่จะไป

การเชื่อมต่อกับนามแฝงประเภท

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.