דילוג לתוכן
  • דף הבית
  • קטגוריות
  • פוסטים אחרונים
  • משתמשים
  • חיפוש
  • חוקי הפורום
כיווץ
תחומים

תחומים - פורום חרדי מקצועי

💡 רוצה לזכור קריאת שמע בזמן? לחץ כאן!
  1. דף הבית
  2. תכנות
  3. פונקציית callback לא קבועה, מהי הדרך המומלצת להגדיר את ה-Type של הקולבאק (TS)

פונקציית callback לא קבועה, מהי הדרך המומלצת להגדיר את ה-Type של הקולבאק (TS)

מתוזמן נעוץ נעול הועבר תכנות
3 פוסטים 2 כותבים 230 צפיות
  • מהישן לחדש
  • מהחדש לישן
  • הכי הרבה הצבעות
התחברו כדי לפרסם תגובה
נושא זה נמחק. רק משתמשים עם הרשאות מתאימות יוכלו לצפות בו.
  • מוטי אורןמ מנותק
    מוטי אורןמ מנותק
    מוטי אורן
    כתב ב נערך לאחרונה על ידי מוטי אורן
    #1

    יש לי מחלקה בשם Instructions, שיש לה מתודה סטטית עם השם operate.
    המתודה הנ"ל מקבלת שני ארגומנטים וודאים, ועוד שנים אפשריים: הראשון הוא פונקציית callback שהיא צריכה להעביר לה ארגומנטים ולקרוא לה, ושאר הארגומנטים הם אותם הארגומנטים שיועברו לפונקציית ה-callback.
    פונקציית ה-callback יכולה להיות אחת מתוך שלושה סוגי פונקציות: הסוג הראשון מקבל ארגומנט אחד ומבצע עליו פעולה מסוימת, הסוג השני מקבל שני ארגומנטים, והשלישי מקבל שלושה ארגומנטים. הספק שלי הוא איך להתייחס ל-Type של ה-callback הנ"ל.

    בהתחלה חשבתי ליישם את זה בערך בצורה כזו:

    interface Operand {
      // ...
    }
    
    interface OperationFunc {
      (dstOperand: Operand, srcOperand?: Operand, powerEvaluation?: number): void;
    }
    
    class Instructions {
      static operate (callback: OperationFunc, dstOperand, srcOperand?, powerEvaluation?) {
        callback(dstOperand, srcOperand, powerEvaluation);
      }
    }
    

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

    בעקבות הבעיה הנ"ל, חשבתי להפוך את המתודה operate לגנרית, שמקבלת את ה-Type של ה-callback, ואת שאר הארגומנטים היא מקבלת כאובייקט נפרד (בשביל האובייקט הזה היא מקבלת Type גנרי נוסף). משהו כזה:

    interface Operand {
      // ...
    }
    
    interface UnaryOperation {
      (dstOperation: Operand): void;
    }
    interface BinaryOperation {
      (dstOperand: Operand, srcOperand: Operand): void;
    }
    interface SignBinaryOperation {
      (dstOperand: Operand, srcOperand: Operand, powerEvaluation: number): void;
    }
    
    interface UnaryOperationArgs {
      dstOperand: Operand;
    }
    interface BinaryOperationArgs extends UnaryOperationArgs {
      srcOperand: Operand;
    }
    interface SignBinaryOperationArgs extends BinaryOperationArgs {
      powerEvaluation: number;
    }
    
    class Instructions {
      static operate<OperationType = UnaryOperation | BinaryOperation | SignBinaryOperation, OperationArgs = UnaryOperationArgs | BinaryOperationArgs | SignBinaryOperationArgs> (callback: OperationType, operationArgs: OperationArgs) {
        callback(operationArgs);
      }
    }
    

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

    אבל אני עדיין לא מרוצה מכמה סיבות. הראשונה היא, שאני לא יכול להיות מרוצה כל עוד TSC לא מרוצה, ומכיוון שהוא לא יכול לדעת מראש שה-callback שיועבר לו אמור לקבל את אותו אובייקט ארגומנטים, הוא זורק שגיאה על כך.

    והסיבה השנייה היא שהקוד (לטעמי לפחות) נראה זוועה ככה, וחייבת להיות דרך יותר אלגנטית לעשות דבר כזה...

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

    רפאלר תגובה 1 תגובה אחרונה
    2
    • רפאלר מנותק
      רפאלר מנותק
      רפאל
      השיב למוטי אורן ב נערך לאחרונה על ידי רפאל
      #2

      המתודה Operate איננה מקבלת כל אינדיקציה על טיב הפעולה שהיא אמורה לבצע, ניתן להסיק את אחת משתי האפשרויות:

      1. שהיא תבדוק בעצמה (Runtime type checking) לפי מספר הפרמטרים שסופקו
      2. טיב הפעולה אינו רלוונטי עבורה

      כדי לשפר את הType-Safety עבור הקוד שיעשה שימוש במתודה, ניתן לעשות שימוש בFunction Overloading:

      class Instructions {
        public static operate(callback: UnaryOperation, dst: number)
        public static operate(callback: BinaryOperation, dst: number, src: number)
        public static operate(callback: SignBinaryOperation, dst: number, src: number, powerEvaluation: number)
        public static operate(callback: Function, dst: number, src?: number, powerEvaluation?: number) {
          // Note: You'll have to do type checking manually
          // here if you want differing behavior based on the required operation type
        }
      }
      

      שימוש:

      operate((x) => { }, 1) // Works. Operation: Unary
      operate((x, y, z) => { }, 1, 2) // Fails (x, y, z) => void' is not assignable to parameter of type 'BinaryOperation
      operate((x, y, z) => { }, 1, 2, 3) // Works. Operation:  SignBinary
      
      

      נ.ב. שימוש בUnion Types לא יפתור את הבעיה, משום שהסוג המדויק של OperationType לעולם לא יהיה ידוע בתוך המתודה בזמן כתיבת הקוד.

      תגובה 1 תגובה אחרונה
      3
      • מוטי אורןמ מנותק
        מוטי אורןמ מנותק
        מוטי אורן
        כתב ב נערך לאחרונה על ידי מוטי אורן
        #3
        פוסט זה נמחק!
        תגובה 1 תגובה אחרונה
        2
        • מוטי אורןמ מוטי אורן התייחס לנושא זה ב

        בא תתחבר לדף היומי!
        • התחברות

        • אין לך חשבון עדיין? הרשמה

        • התחברו או הירשמו כדי לחפש.
        • פוסט ראשון
          פוסט אחרון
        0
        • דף הבית
        • קטגוריות
        • פוסטים אחרונים
        • משתמשים
        • חיפוש
        • חוקי הפורום