การวิเคราะห์แบบคงที่

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

ESLint

ESLint เป็นเครื่องมือที่สามารถให้ความคิดเห็นเกี่ยวกับปัญหาที่อาจเกิดขึ้นในฐานของโค้ด ปัญหาเหล่านี้อาจเป็นไปได้ว่าปลอดภัย แต่ข้อผิดพลาดหรือลักษณะการทำงานที่ไม่เป็นไปตามมาตรฐานนั้นเกิดขึ้นเอง ESLint ให้คุณใช้กฎจำนวนหนึ่งที่มีการตรวจสอบในฐานของโค้ด รวมทั้งหลายกฎในชุด "แนะนำ"

ตัวอย่างที่ดีของกฎ ESLint คือกฎ no-unsafe-finally ซึ่งป้องกันไม่ให้คุณเขียนคำสั่งที่แก้ไขขั้นตอนการควบคุมโปรแกรมภายในบล็อก finally นี่เป็นกฎที่ดี เพราะการทำเช่นนี้เป็นวิธีแปลกๆ ในการเขียน JavaScript ซึ่งยากต่อการควบคุม แต่กระบวนการตรวจทานโค้ดที่ดีควรตรวจพบได้

  try {
    const result = await complexFetchFromNetwork();
    if (!result.ok) {
      throw new Error("failed to fetch");
    }
  } finally {
    // warning - this will 'overrule' the previous exception!
    return false;
  }

ดังนั้น ESLint จึงไม่ใช่สิ่งที่มาแทนกระบวนการตรวจสอบที่มีประสิทธิภาพ (และคู่มือแนะนำรูปแบบที่ระบุว่าโค้ดเบสควรมีลักษณะอย่างไร) เนื่องจากนักพัฒนาซอฟต์แวร์ไม่ได้สามารถบันทึกแนวทางแบบนอกรีตดอกซ์ทั้งหมดที่นักพัฒนาซอฟต์แวร์อาจพยายามใส่ไว้ในฐานของโค้ดได้ คู่มือแนวทางปฏิบัติด้านภาษาอังกฤษของ Google มีส่วนสั้นๆ เกี่ยวกับ "การทำให้ใช้งานได้ง่าย"

ESLint ให้คุณละเมิดกฎและใส่คำอธิบายประกอบโค้ดเป็น "อนุญาต" ได้ ตัวอย่างเช่น คุณอนุญาตตรรกะก่อนหน้านี้ได้ด้วยการใส่คำอธิบายประกอบดังนี้

  finally {
    // eslint-disable-next-line no-unsafe-finally
    return false;
  }

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

สุดท้าย การเปิดใช้เครื่องมือวิเคราะห์แบบคงที่ในฐานของโค้ดขนาดใหญ่อาจสร้างข้อผิดพลาดที่ไม่เป็นประโยชน์ (และงานที่ยุ่งจนต้องเปลี่ยนโครงสร้างภายใน) มากกว่าโค้ดที่ปกติดี จึงเป็นเรื่องง่ายที่จะเปิดใช้ตั้งแต่ช่วงแรกของวงจรโปรเจ็กต์

ปลั๊กอิน ESLint สำหรับการสนับสนุนเบราว์เซอร์

คุณสามารถเพิ่มปลั๊กอินลงใน ESLint เพื่อแจ้งการใช้งาน API ที่ไม่มีการรองรับอย่างกว้างขวางหรือไม่รองรับโดยรายการเบราว์เซอร์เป้าหมายได้ แพ็กเกจ eslint-plugin-compat จะเตือนให้คุณทราบเมื่อ API อาจไม่พร้อมใช้งานสำหรับผู้ใช้ คุณจึงไม่จำเป็นต้องติดตามดูอยู่เสมอ

การตรวจสอบประเภทสำหรับการวิเคราะห์แบบคงที่

เมื่อเรียนรู้ JavaScript นักพัฒนาซอฟต์แวร์ใหม่ๆ มักแนะนำให้คิดว่าเป็นภาษาที่พิมพ์ไม่ค่อยดี กล่าวคือ คุณสามารถประกาศตัวแปรเป็นประเภทหนึ่ง จากนั้นจึงใช้ตำแหน่งเดียวกันสำหรับสิ่งที่แตกต่างไปโดยสิ้นเชิง ซึ่งคล้ายกับ Python และภาษาสคริปต์อื่นๆ แต่ต่างจากภาษาที่คอมไพล์ เช่น C/C++ และ Rust

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

TypeScript

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

เพื่อเป็นตัวอย่างสั้นๆ โค้ดนี้ ซึ่งคาดว่าจะควรได้รับการเรียกกลับที่ยอมรับชื่อ string และอายุ number:

const callback = (name: string, age: string): void => {
  console.info(name, 'is now', age, 'years old!');
};
onBirthday(callback);

สร้างข้อผิดพลาดต่อไปนี้เมื่อเรียกใช้ผ่าน TypeScript หรือแม้กระทั่งเมื่อวางเมาส์เหนือ IDE

bad.ts:4:12 - error TS2345: Argument of type '(name: string, age: string) => void' is not assignable to parameter of type '(name: string, age: number) => void'.
  Types of parameters 'age' and 'age' are incompatible.
    Type 'number' is not assignable to type 'string'.

4 onBirthday(callback);
             ~~~~~~~~

Found 1 error in bad.ts:4
โค้ดจากตัวอย่างก่อนหน้านี้ที่แสดงใน IDE พร้อมข้อความแสดงข้อผิดพลาดที่แสดงในป๊อปอัป
VSCode ระบุว่าคุณส่งผ่านประเภท ที่ไม่ถูกต้อง

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

ส่วนที่ยากที่สุดของการใช้ TypeScript คือการตั้งค่าอย่างถูกต้อง ทุกโปรเจ็กต์ต้องมีไฟล์ tsconfig.json ซึ่งแม้ว่าเครื่องมือบรรทัดคำสั่ง tsc จะใช้เป็นหลัก แต่ IDE เช่น VSCode ยังอ่านเครื่องมือและเครื่องมือสร้างอื่นๆ ได้อีกมากมาย ซึ่งรวมถึง Vitest ไฟล์นี้มีตัวเลือกและแฟล็กหลายร้อยรายการ และคุณสามารถค้นหาแหล่งข้อมูลดีๆ สำหรับการตั้งค่าได้ที่นี่

เคล็ดลับ TypeScript ทั่วไป

เมื่อตั้งค่าและใช้ TypeScript ผ่านไฟล์ tsconfig.json โปรดคำนึงถึงสิ่งต่อไปนี้

  • ตรวจสอบให้แน่ใจว่าได้รวมและตรวจสอบไฟล์ต้นฉบับแล้ว หากไฟล์ใดที่ "ไม่มีข้อผิดพลาด" อย่างลึกลับ นั่นอาจเป็นเพราะไฟล์นั้นยังไม่ได้รับการตรวจสอบ
  • การอธิบายประเภทและอินเทอร์เฟซภายในไฟล์ .d.ts อย่างชัดแจ้ง จะทำให้ทดสอบฐานของโค้ดได้ง่ายขึ้นโดยไม่ต้องอธิบายโดยปริยายเมื่อเขียนฟังก์ชัน การเขียนการจำลองและโค้ดเวอร์ชัน "ปลอม" จะทำได้ง่ายขึ้นเมื่ออินเทอร์เฟซที่เกี่ยวข้องชัดเจน

TypeScript โดยนัย

หนึ่งในตัวเลือกการกำหนดค่าที่มีประสิทธิภาพและคุ้มค่ามากที่สุดของ TypeScript คือแฟล็ก noImplicitAny แต่ก็มักจะเปิดใช้งานได้ยากที่สุด โดยเฉพาะหากคุณมีฐานของโค้ดขนาดใหญ่อยู่แล้ว (ระบบจะเปิดใช้แฟล็ก noImplicitAny โดยค่าเริ่มต้นหากคุณอยู่ในโหมด strict แต่ไม่ได้เปิดใช้)

การตั้งค่าสถานะนี้จะทำให้ฟังก์ชันนี้แสดงผลข้อผิดพลาด

export function fibonacci(n) {
  if (n <= 1) {
    return 0;
  } else if (n === 2) {
    return 1;
  }
  return fibonacci(n - 1) + fibonacci(n - 2);
}

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

function fibonacci(n: any): any

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

วิธีแก้ไขง่ายๆ คือทำเครื่องหมายทั้งอาร์กิวเมนต์ n และประเภทการแสดงผลของ fibonacci เป็น number

แฟล็ก noImplicitAny ไม่ได้ป้องกันคุณจากการเขียน any ในฐานของโค้ดอย่างชัดแจ้ง คุณยังคงเขียนฟังก์ชันที่ยอมรับหรือแสดงผลประเภท any ได้ เพียงแต่ช่วยให้คุณกำหนดประเภทให้กับตัวแปรทั้งหมดได้