שב רגע בצד טייפסקריפט, אני צריך לעבוד

12/04/2024

נתבונן בשתי פונקציות בטייפסקריפט שמשתמשות במערכת הטיפוסים של קיסלי עבור גישה לבסיס נתונים SQL:

async editNote(username: string, noteId: number, newText: string) {
  const user = await db.selectFrom('users').selectAll().where('users.name', '=', username).executeTakeFirstOrThrow();

  return db
    .updateTable('notes')
    .set('text', newText)
    .where(noteBelongsToUser(user.id, noteId))
    .returningAll()
    .executeTakeFirstOrThrow()
},

async deleteNote(username: string, noteId: number) {
  const user = await db.selectFrom('users').selectAll().where('users.name', '=', username).executeTakeFirstOrThrow();

  return db
    .deleteFrom('notes')
    .where(noteBelongsToUser(user.id, noteId))
    .returningAll()
    .executeTakeFirstOrThrow()
},

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

ניסיון לאחד אותן ולבטל את הקוד המשותף עשוי להיראות כך:

async function dry(db: Kysely<Database>, 
  username: string,
  noteId: number,
  f: (db: Kysely<Database>) => ???) {
  const user = await db.selectFrom('users').selectAll().where('users.name', '=', username).executeTakeFirstOrThrow();

  return f(db)
    .where(noteBelongsToUser(user.id, noteId))
    .returningAll()
    .executeTakeFirstOrThrow()
}

הקוד הזה עובד ואפשר להשתמש בו בקלות למשל:

async easyDeleteNote(username: string, noteId: number) {
  dry(db, username, noteId, (db) => db.deleteFrom('notes'))
}

יש רק בעיה אחת, סימן אחד שחסר לי - מה מחזירה הפונקציה f ? מה לכתוב במקום סימני השאלה?

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

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