Sanyanggae LogoSanyanggae

📱 การพัฒนาสำหรับมือถือและแอป

Conditional type และ infer ใน TypeScript: ตรวจการแปลงชนิดด้วยตัวอย่างเล็ก

ดู conditional type การกระจาย union และ template literal ผ่านตัวอย่าง พร้อมแยกการตรวจตอนรัน

사냥개 (Sanyanggae)เผยแพร่ ปรับปรุง 6 นาที

นี่คือฉบับแปลจากต้นฉบับภาษาเกาหลี ต้นฉบับภาษาเกาหลี · การตรวจทานคำแปล: ตรวจทานโดยเอไอ

แผนภาพอธิบาย: Conditional type · infer และกระจาย · ตรวจตอนรัน Conditional type และ infer ใน TypeScript: ตรวจการแปลงชนิดด้วยตัวอย่างเล็ก
จัดทำโดย Sanyanggae · แผนภาพอธิบาย · Conditional type · infer และกระจาย · ตรวจตอนรัน

เมื่อประกาศชนิดคล้ายซ้ำใน TypeScript เราหาวิธีคำนวณชนิดผลจากชนิดเข้า สำคัญกว่าตัวอักษรสั้นคือความสัมพันธ์ชนิดชัดต่อผู้อ่านหรือไม่ บทใช้บริการแจ้งจัดส่งสมมุติเพื่อดู conditional type กับ infer แยกจากงานตรวจข้อมูลภายนอกถูกจริง

1. Conditional type เป็นสาขาที่รับชนิดเข้า

เอกสาร conditional type ทางการ อธิบายไวยากรณ์เลือกผลตาม extends ตัวอย่างสร้างชนิด literal boolean ตามเป็นชนิด string หรือไม่ ไม่ใช่ฟังก์ชันตรวจ string ตอนทำงาน

type IsText<T> = T extends string ? true : false;
type NameIsText = IsText<'parcel'>; // true
type CountIsText = IsText<3>;       // false

สมมุติฟังก์ชันแจ้งรับรหัส string แต่ฟังก์ชันในรับเลข ก่อนใช้ conditional type ต้องอธิบายเหตุแยกสองรหัส ต่างความหมายจริงชื่อแยกช่วย ถ้าต่างเพียงเขียน ทำ input เดียวอาจอ่านง่าย อย่าใช้เทคนิคชนิดซ่อนข้อมูลออกแบบกำกวม

ตรวจชนิดเขียน input กับผลคาดเป็นคู่ แยก string เลข union และผิดคาดเป็นตัวอย่างเล็กลดภาระอ่านซับซ้อน ดูผลในคอมเมนต์ตรงชนิด editor อนุมานไหม ชื่อดูธรรมชาติแต่คำนวณจริงอาจต่าง

2. การกระจาย union เปลี่ยนความหมายอาร์เรย์

พารามิเตอร์ชนิดตรงซ้ายเงื่อนไขทำกระจายไปแต่ละสมาชิก union ถ้าจะหยุดและถือ union ทั้งหมดเป็นหนึ่ง เทียบรูปห่อวงเล็บเหลี่ยม

type SeparateLists<T> = T extends unknown ? T[] : never;
type Together<T> = [T] extends [unknown] ? T[] : never;
type A = SeparateLists<string | number>; // string[] | number[]
type B = Together<string | number>;      // (string | number)[]
const a: A = ['a', 'b'];
const b: B = ['a', 1];

แรกคืออาร์เรย์เฉพาะ string หรือเฉพาะเลข หลังให้ string กับเลขในอาร์เรย์เดียว ผลเหมาะต่างตามรายการจัดส่งทั้งหมดต้องรหัสแบบเดียวหรือแต่ละรายการต่างได้ เห็นวงเล็บเหมือนแต่สัญญาไม่เดียว

งานจริงมีปัญหาให้ใส่ input ทีละสมาชิก แทนอ่าน utility ซับซ้อนทั้งหมด เทียบผล string เลขและ union ทั้งสอง ชัดว่าจงใจกระจายไหมก็อธิบายเหตุเพิ่มวงเล็บได้ บันทึกตรวจชนิดให้มีตัวอย่างค่าจะอนุญาต ไม่ใช่ผลสุดท้ายอย่างเดียว

3. infer ตั้งชื่อและดึงชนิดจากโครงสร้าง

infer ใช้ตั้งชื่อส่วนโครงที่จับคู่ใน conditional type ต่อไปเป็นชนิดเล็กถอด Promise หนึ่งชั้น

type OneResult<T> = T extends Promise<infer Value> ? Value : T;
type Parcel = OneResult<Promise<{ tracking: string }>>;
type ParcelList = OneResult<Promise<string[]>>;

โค้ดไม่รันหรือรองานอะซิงก์ แต่บอกรูปผลตอนคอมไพล์ ตั้งชื่อฟังก์ชัน Resolved อาจให้รู้สึกค่าเข้ามาแล้ว จึงดูบริบทที่ใช้ด้วย การรอตอนรันยังจัดด้วยโค้ดอะซิงก์

ถ้าต้องชนิดผลรอแบบเวียน ให้ดู utility มาตรฐาน Awaited ก่อนขยายตัวอย่างชั้นเดียวเองต่อ ความง่ายชนิดเพื่อสอนต่างข้อกำหนดเครื่องมือร่วม ทีมใช้ utility ใหม่ควรจด input ที่ผลต่างจากมาตรฐานกับเหตุจำเป็น

4. เชื่อมชื่อเหตุการณ์ด้วย template literal

Template literal type แสดงชุด literal string เป็นชนิด บริการส่งของอาจใช้ชื่อเหตุการณ์รวมขอบเขตกับการกระทำ

type Scope = 'parcel' | 'address';
type Action = 'created' | 'updated';
type EventName = `${Scope}:${Action}`;
const event: EventName = 'parcel:created';

สะกดชื่อผิดพบตอนคอมไพล์ แต่ทุกการรวมใช้ได้จริงไหมอีกเรื่อง เช่น ถ้ารองรับเฉพาะลบที่อยู่ ผลคูณขอบเขต-การกระทำอาจแทนกฎไม่ตรง ให้คิดแบบจับคู่เหตุการณ์อนุญาตกับ payload ชัดก่อน

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

5. JSON ภายนอกต้องตรวจตอนรัน

แค่ติดชนิด User หรือ Parcel ให้ API ไม่ประกันคำตอบจริงรูปนั้น ดูรูปเล็กรับค่าภายนอก unknown แล้วตรวจฟิลด์จำเป็น

function hasTracking(value: unknown): value is { tracking: string } {
  return typeof value === 'object' && value !== null
    && 'tracking' in value && typeof value.tracking === 'string';
}
const incoming: unknown = { tracking: 'DEMO-001' };
if (hasTracking(incoming)) console.log(incoming.tracking);

ตรวจนี้รู้เพียง tracking เป็น string ไม่รู้เลขติดตามมีจริงหรือผู้ใช้มีสิทธิ์ดู แยก narrowing กฎธุรกิจและตรวจสิทธิ์เป็นหน้าที่ต่าง เอกสาร Narrowing ทางการ บอกข้อมูลชนิดแคบลงผ่านเงื่อนไข

6. ลำดับตรวจเล็กเพื่อเลือกเครื่องมือชนิด

ก่อนเขียนค่าจริงอนุญาตสอง ปฏิเสธสอง ต่อใช้ union ธรรมดากับประกาศ object ชัดให้ความหมาย เหลือสัมพันธ์ซ้ำค่อย conditional type หรือ infer จะชัดเหตุเทคนิค หากอ่านประกาศนานขึ้นมาก เลือกแค่ส่วนร่วมออก ส่วนเหลือชนิดธรรมดาได้

ท้ายรันตรวจชนิดกับรันไทม์แยก การดู compiler ปฏิเสธชื่อเหตุการณ์ผิดกับโปรแกรมอธิบายผิดเมื่อเซิร์ฟเวอร์ขาดฟิลด์ช่วยกัน ตรวจผลเล็กแล้วเชื่อมถึงขอบ input จริงจึงให้การแปลงชนิดช่วยแอปปลอดภัย

หลักฐานและเอกสารอ้างอิง

  • Conditional Types

    TypeScript · วันที่เข้าถึงข้อมูล

  • Template Literal Types

    TypeScript · วันที่เข้าถึงข้อมูล

  • Utility Types

    TypeScript · วันที่เข้าถึงข้อมูล

  • Narrowing

    TypeScript · วันที่เข้าถึงข้อมูล

บทความนี้อธิบายจากข้อมูลสาธารณะ การอ้างอิงองค์กรไม่ได้หมายความว่าองค์กรนั้นตรวจทานหรือรับรองบทความ

เกี่ยวกับผู้ดูแลและการติดต่อ

บทความในหัวข้อเดียวกัน