ฉันจะสร้างวัตถุตามข้อกำหนดของไฟล์อินเตอร์เฟสใน TypeScript ได้อย่างไร


313

ฉันได้กำหนดอินเทอร์เฟซเช่นนี้:

interface IModal {
    content: string;
    form: string;
    href: string;
    $form: JQuery;
    $message: JQuery;
    $modal: JQuery;
    $submits: JQuery;
 }

ฉันกำหนดตัวแปรเช่นนี้

var modal: IModal;

อย่างไรก็ตามเมื่อฉันพยายามที่จะตั้งค่าคุณสมบัติของคำกริยามันทำให้ฉันมีข้อความบอกว่า

"cannot set property content of undefined"

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

คำตอบ:


426

หากคุณกำลังสร้างตัวแปร "modal" ที่อื่นและต้องการบอก TypeScript ทุกอย่างจะเสร็จสิ้นคุณจะใช้:

declare const modal: IModal;

หากคุณต้องการสร้างตัวแปรที่จะเป็นอินสแตนซ์ของ IModal จริง ๆ ใน TypeScript คุณจะต้องกำหนดตัวแปรทั้งหมด

const modal: IModal = {
    content: '',
    form: '',
    href: '',
    $form: null,
    $message: null,
    $modal: null,
    $submits: null
};

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

const modal = {} as IModal;

คลาสตัวอย่าง

class Modal implements IModal {
    content: string;
    form: string;
    href: string;
    $form: JQuery;
    $message: JQuery;
    $modal: JQuery;
    $submits: JQuery;
}

const modal = new Modal();

คุณอาจคิดว่า "เฮ้จริง ๆ แล้วมันคือการทำซ้ำอินเทอร์เฟซ" - และคุณถูกต้อง หากคลาส Modal เป็นการใช้งานส่วนต่อประสาน IModal เพียงอย่างเดียวคุณอาจต้องการลบส่วนติดต่อทั้งหมดและใช้ ...

const modal: Modal = new Modal();

ค่อนข้างมากกว่า

const modal: IModal = new Modal();

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

1
ใช่ - คุณสามารถกำหนดคลาสและจากนั้นคุณจะต้องสร้างอินสแตนซ์ใหม่เมื่อคุณต้องการเท่านั้น คุณต้องการตัวอย่างหรือไม่?
เฟนตัน

2
ฉันได้เพิ่มตัวอย่างและหมายเหตุเกี่ยวกับอินเทอร์เฟซ
เฟนตัน

21
var modal = <IModal>{};นี่คือสิ่งที่ฉันกำลังมองหา ;-) ขอบคุณ!
ตำนาน

5
FYI มันจะดีกว่าที่จะใช้มากกว่า{} as IModal <IModal>{}มันลบความคลุมเครือในไวยากรณ์ภาษาเมื่อใช้การ<foo>ยืนยันสไตล์ใน JSX อ่านเพิ่มเติม และแน่นอนใช้letหรือแทนconst var
อเล็กซ์

191

หากคุณต้องการวัตถุว่างของอินเทอร์เฟซคุณสามารถทำได้เพียง:

var modal = <IModal>{};

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

class TestClass {
    a: number;
    b: string;
    c: boolean;
}

รวบรวมเป็น

var TestClass = (function () {
    function TestClass() {
    }
    return TestClass;
})();

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


1
`เพื่อเพิ่มความคิดเห็นข้างต้น ในการเรียกใช้ฟังก์ชัน "updateModal (IModal modalInstance) {}" คุณสามารถสร้างอินสแตนซ์อินไลน์ของอินเทอร์เฟซ 'IModal' เช่นนี้: // รหัสบางส่วนที่นี่ที่สามารถเข้าถึงฟังก์ชั่น updateModal และ IModal: {// บรรทัดนี้สร้างเนื้อหาอินสแตนซ์: '', แบบฟอร์ม: '', href: '', $ form: null, $ message: null, $ modal: null, $ submits: null}); // กรอกโค้ดให้ครบถ้วน `
ซันนี่

โดยการใช้var modal= <abc>{}เราเพิ่งได้รับ modal ประเภท abc ของวัตถุที่ว่างเปล่า แต่ที่เราได้ประกาศประเภทของ modal? ฉันใช้ typescript6
Pardeep Jain

สิ่งนี้ไม่ได้ผลสำหรับฉันฉันต้องเริ่มต้นวัตถุทั้งหมดตามที่ระบุไว้ในคำตอบที่ยอมรับ
ราหุลซอน

52

หากคุณกำลังใช้ React ตัวแยกวิเคราะห์จะทำให้หายใจไม่ออกในไวยากรณ์ cast ดั้งเดิมเพื่อให้มีการแนะนำทางเลือกอื่นเพื่อใช้ในไฟล์. tsx

let a = {} as MyInterface;

https://www.typescriptlang.org/docs/handbook/jsx.html


22

ฉันคิดว่าคุณมีตัวเลือกต่างกันห้าแบบจะทำเช่นนั้น การเลือกระหว่างพวกเขาอาจเป็นเรื่องง่ายขึ้นอยู่กับเป้าหมายที่คุณต้องการบรรลุ

วิธีที่ดีที่สุดในกรณีส่วนใหญ่เพื่อใช้คลาสและสร้างอินสแตนซ์เนื่องจากคุณใช้ TypeScript เพื่อใช้การตรวจสอบชนิด

interface IModal {
    content: string;
    form: string;
    //...

    //Extra
    foo: (bar: string): void;
}

class Modal implements IModal {
    content: string;
    form: string;

    foo(param: string): void {
    }
}

แม้ว่าวิธีการอื่นจะเสนอวิธีที่ง่ายกว่าในการสร้างวัตถุจากส่วนต่อประสานคุณควรพิจารณาแยกส่วนต่อประสานออกจากกันถ้าคุณกำลังใช้วัตถุของคุณสำหรับเรื่องต่าง ๆ และไม่ทำให้ส่วนต่อประสาน:

interface IBehaviour {
    //Extra
    foo(param: string): void;
}

interface IModal extends IBehaviour{
    content: string;
    form: string;
    //...
}

ในทางกลับกันตัวอย่างเช่นระหว่างการทดสอบหน่วยรหัสของคุณ (ถ้าคุณไม่ใช้การแยกข้อกังวลบ่อย) คุณอาจยอมรับข้อเสียเพื่อประสิทธิภาพในการทำงาน คุณอาจใช้วิธีการอื่นเพื่อสร้าง mocks ส่วนใหญ่สำหรับอินเทอร์เฟซ * .d.ts ของบุคคลที่สามที่มีขนาดใหญ่ และมันอาจเป็นความเจ็บปวดที่จะใช้วัตถุที่ไม่ระบุชื่อเต็มรูปแบบสำหรับทุก ๆ อินเทอร์เฟซขนาดใหญ่

บนเส้นทางนี้ตัวเลือกแรกของคุณคือสร้างวัตถุว่างเปล่า :

 var modal = <IModal>{};

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

var modal: IModal = {
    content: '',
    form: '',
    //...

    foo: (param: string): void => {
    }
};

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

var modal: IModal = <any>{
    foo: (param: string): void => {

    }
};

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



12

เนื่องจากฉันไม่พบคำตอบที่เท่ากันในด้านบนและคำตอบของฉันแตกต่างกัน ฉันทำ:

modal: IModal = <IModal>{}

2

คุณสามารถใช้ส่วนต่อประสานของคุณได้

class Modal() {
  constructor(public iModal: IModal) {
   //You now have access to all your interface variables using this.iModal object,
   //you don't need to define the properties at all, constructor does it for you.
  }
}

2

นี่คือวิธีการอื่น:

คุณสามารถสร้างวัตถุที่เป็นมิตรกับ ESL ได้เช่นนี้

const modal: IModal = {} as IModal;

หรืออินสแตนซ์เริ่มต้นที่ยึดตามอินเทอร์เฟซและมีค่าเริ่มต้นที่สมเหตุสมผลหากมี

const defaultModal: IModal = {
    content: "",
    form: "",
    href: "",
    $form: {} as JQuery,
    $message: {} as JQuery,
    $modal: {} as JQuery,
    $submits: {} as JQuery
};

จากนั้นการแปรผันของอินสแตนซ์เริ่มต้นง่ายๆโดยการแทนที่คุณสมบัติบางอย่าง

const confirmationModal: IModal = {
    ...defaultModal,     // all properties/values from defaultModal
    form: "confirmForm"  // override form only
}

1

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

สำหรับผู้ที่สนใจในโซลูชันที่กะทัดรัดและมีประสิทธิภาพอื่น ๆ:

ตัวเลือก 1: ยกตัวอย่างคลาสที่ไม่ระบุตัวตนซึ่งใช้อินเทอร์เฟซ:

new class implements MyInterface {
  nameFirst = 'John';
  nameFamily = 'Smith';
}();

ตัวเลือก 2: สร้างฟังก์ชันยูทิลิตี้:

export function impl<I>(i: I) { return i; }

impl<MyInterface>({
  nameFirst: 'John';
  nameFamily: 'Smith';
})

0

คุณสามารถตั้งค่าเริ่มต้นโดยใช้ Classคุณสามารถตั้งค่าเริ่มต้นโดยใช้

ไม่มีตัวสร้างคลาส:

interface IModal {
  content: string;
  form: string;
  href: string;
  isPopup: boolean;
};

class Modal implements IModal {
  content = "";
  form = "";
  href: string;  // will not be added to object
  isPopup = true;
}

const myModal = new Modal();
console.log(myModal); // output: {content: "", form: "", isPopup: true}

ด้วย Class Constructor

interface IModal {
  content: string;
  form: string;
  href: string;
  isPopup: boolean;
}

class Modal implements IModal {
  constructor() {
    this.content = "";
    this.form = "";
    this.isPopup = true;
  }

  content: string;

  form: string;

  href: string; // not part of constructor so will not be added to object

  isPopup: boolean;
}

const myModal = new Modal();
console.log(myModal); // output: {content: "", form: "", isPopup: true}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.