איך אני יכול ליצור אובייקט על בסיס הגדרת קובץ ממשק ב-TypeScript?


הגדרתי ממשק כך:

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"

האם בסדר להשתמש בממשק כדי לתאר את אובייקט המודל שלי ואם כן, איך אני צריך ליצור אותו?

תשובה #1

אם אתה יוצר את המשתנה "modal" במקום אחר, ורוצה להגיד ל-TypeScript שהכל יושלם, תשתמש ב:

declare const modal: IModal;

אם אתה רוצה ליצור משתנה שיהיה למעשה מופע של IModal ב-TypeScript תצטרך להגדיר אותו במלואו.

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

או לשקר, עם הצהרת טיפוס, אבל תאבד את בטיחות הטיפוס שלך כיוון שעכשיו תקבל undefined במקומות בלתי צפויים, ואולי שגיאות בזמן ריצה, כאשר תנסה לגשת ל-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

אם אתה רוצה אובייקט ריק של ממשק, אתה יכול פשוט לעשות את זה:

var modal = <IModal>{};

היתרון בשימוש בממשקים במקום מחלקות למבנה נתונים הוא שאם אין לך שום שיטות על המחלקה, זה יופיע בקוד JS הממוּלָא כשיטה ריקה. לדוגמה:

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

מְתֻכְנֵת לְתוֹךְ

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

שאינו נושא ערך. מצד שני, ממשקים אינם מופיעים ב-JS כלל בעוד שהם מספקים את היתרונות של מבנה נתונים ובדיקת סוגים.

תשובה #3

אם אתה משתמש ב-React, הפרסר יתקשה עם התחביר המסורתי של ההמרה ולכן הוצג חלופה לשימוש בקבצי .tsx

let a = {} as MyInterface;

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

תשובה #4

יש 5 דרכים להשתמש בממשק.

 interface IStudent {
          Id: number;
          name: string;
        }
        
        
        Method 1. all fields must assign data.
         const  obj1: IStudent = { Id: 1, name: 'Naveed' };  
        
        Method 2. my favorite one
        const obj2 = { name: 'Naveed' } as IStudent ;
        
        Method 3.
        const obj3 = <IStudent >{name: 'Naveed'}; 
        
        Method 4. use partial interface if all fields not required.
        const  obj4: Partial<IStudent > = { name: 'Naveed' };  
        
        Method 5. use ? Mark with interface fields if all fields not required.
        const  obj5: IStudent = {  name: 'Naveed' };  

תשובה #5

אני חושב שלמעשה יש לך חמישה אופציות שונות לעשות זאת. הבחירה ביניהן יכולה להיות קלה בהתאם למטרה שתרצה להשיג.

הדרך הטובה ביותר ברוב המקרים היא להשתמש במחלקה וליצור מופע שלה, כי אתה משתמש ב-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 קיימת כדי לספק רמת הפשטה חדשה, אם משתמשים בה בחוכמה ובעקביות. אני חושב, רק משום שאפשר להתעלם מהם ברוב המקרים מהקוד שלך, לא צריך לעשות זאת.

תשובה #6

אתה יכול לעשות

var modal = {} as IModal 

תשובה #7

הנה גישה נוספת:

אתה יכול פשוט ליצור אובייקט ידידותי ל-ESLint כמו זה

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
}

תשובה #8

מאז שלא מצאתי תשובה שווה בראש והתשובה שלי שונה. אני עושה:

modal: IModal = <IModal>{}

תשובה #9

כיוון שהשאלה כוללת שימוש ב-TypeScript, החלפה

var modal: IModal;

על ידי

let modal: IModal = {} as IModal;

צריך לענות על השאלה.