Jitrak Blog

Don't use ternary like this

ได้โปรดอย่าใช้ ternary แบบนี้

11 May 2025 15:45

Written by: Yosapol Jitrak

Don't use ternary like this
Tags:

JavaScript

TypeScript

Ternary

เล่าถึง Project A ต่อจากบทความก่อนหน้านี้ Wrong Purpose Destructuring ผมไปเจอ Ternary Operator แบบนี้มาครับ

enum MyType {
  A = 'A',
  B = 'B',
  C = 'C',
  D = 'D',
}

interface MyObjectX {
  type: MyType;
  name: string;
  // Another properties
}

interface MyObjectY {
  type: MyType;
  name: string;
  // Another properties
}

async function execute() {
  const myObjectX: MyObjectX = await fetchMyObjectX();
  const myObjectY: MyObjectY = await fetchMyObjectY();
  // Do a lot of things

  return {
    // Another properties
    x:
      myObjectX.type === MyType.A
        ? `A [${myObjectX.name}]`
        : myObjectX.type === MyType.B
          ? `B [${myObjectX.name}]`
          : myObjectX.type === MyType.C
            ? `C [${myObjectX.name}]`
            : myObjectX.type === MyType.D
              ? `D [${myObjectX.name}]`
              : null,
    y:
      myObjectY.type === MyType.A
        ? `A [${myObjectY.name}]`
        : myObjectY.type === MyType.B
          ? `B [${myObjectY.name}]`
          : myObjectY.type === MyType.C
            ? `C [${myObjectY.name}]`
            : myObjectY.type === MyType.D
              ? `D [${myObjectY.name}]`
              : null,
    // Another properties
  };
}

เจอครั้งแรกถึงกับร้อง WTF ขนาด SonarQube ใน IDE แจ้งเตือน และเหลืองเป็นแผง

SonarQube warning

ถ้าจะขนาดนี้ ผมว่า Switch Statement จะดีกว่าถมเลยครับ

let x: string | null;
switch (myObject.type) {
  case MyType.A:
    x = `A [${myObject.name}]`;
    break;
  case MyType.B:
    x = `B [${myObject.name}]`;
    break;
  case MyType.C:
    x = `C [${myObject.name}]`;
    break;
  case MyType.D:
    x = `D [${myObject.name}]`;
    break;
  default:
    x = null;
}

หรือจะไปใช้ ts-pattern ก็ได้ครับ

import { match } from 'ts-pattern';

interface MyObject {
  type: MyType;
  name: string;
}

interface MyObjectX extends MyObject {
  // Another properties
}

interface MyObjectY extends MyObject {
  // Another properties
}

function getTypeWithName(myObject: MyObject): string | null {
  return match(myObject.type)
    .with(MyType.A, () => `A [${myObject.name}]`)
    .with(MyType.B, () => `B [${myObject.name}]`)
    .with(MyType.C, () => `C [${myObject.name}]`)
    .with(MyType.D, () => `D [${myObject.name}]`)
    .otherwise(() => null);
}

async function execute() {
  const myObjectX: MyObjectX = await fetchMyObjectX();
  const myObjectY: MyObjectY = await fetchMyObjectY();
  // Do a lot of things

  return {
    // Another properties
    x: getTypeWithName(myObjectX),
    y: getTypeWithName(myObjectY),
    // Another properties
  };
}

ดูแล้วอ่านง่ายมากกว่ากันเยอะเลยครับ

เครื่องมือของภาษาสมัยใหม่อำนวยความสะดวก แต่ก็ต้องใช้ให้ถูกต้องด้วยนะครับ

ยังไม่จบนะ เดี๋ยวมีภาคต่อ

ภาคต่อ:
Link: Wrong Purpose Destructuring
Link: Ultimate Join