0Pricing
TypeScript Academy · บทเรียน

การจำลองเครื่องสถานะ

แสดงสถานะที่มีจำนวนจำกัดด้วยยูเนียนแบบจำแนก

การจำลองเครื่องสถานะ เป็นบทเรียน TypeScript Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน TypeScript Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส TypeScript Academy มีบทเรียนทั้งหมด 4 บทเรียน

สถานะในรูปแบบยูเนียนแบบมีตัวจำแนก

ส่วนติดต่อผู้ใช้และลำดับการทำงานแบบอะซิงโครนัสมีสถานะที่แตกต่างกัน ได้แก่ idle, loading, success และ error การสร้างแบบจำลองเป็นยูเนียนแบบมีตัวจำแนกทำให้แต่ละสถานะมีข้อมูลเท่าที่จำเป็นอย่างพอดี

type State =
  | { status: "idle" }
  | { status: "loading" }
  | { status: "success"; data: string }
  | { status: "error"; message: string };

const s: State = { status: "idle" };
console.log(s.status);

ข้อมูลประกอบของแต่ละสถานะ

เฉพาะสถานะ success เท่านั้นที่มี data และเฉพาะ error เท่านั้นที่มี message ส่วน idle และ loading ไม่มีข้อมูลเพิ่มเติม จึงป้องกันไม่ให้ข้อมูลเก่ารั่วไหลข้ามสถานะ

type State =
  | { status: "idle" }
  | { status: "loading" }
  | { status: "success"; data: number[] }
  | { status: "error"; message: string };

const ok: State = { status: "success", data: [1, 2, 3] };
console.log(ok.status, "data" in ok ? ok.data : null);

การแสดงผลแต่ละสถานะ

ฟังก์ชันที่ใช้สวิตช์กับ status สามารถแสดงผลที่ถูกต้องสำหรับแต่ละสถานะได้ โดยฟิลด์ของสมาชิกจะพร้อมใช้งานเฉพาะในจุดที่มีฟิลด์นั้นอยู่

type State =
  | { status: "idle" }
  | { status: "loading" }
  | { status: "success"; data: string }
  | { status: "error"; message: string };

function view(s: State): string {
  switch (s.status) {
    case "idle": return "Ready";
    case "loading": return "Loading...";
    case "success": return "Got: " + s.data;
    case "error": return "Failed: " + s.message;
  }
}
console.log(view({ status: "success", data: "users" }));

การกำหนดการเปลี่ยนสถานะ

เครื่องจักรสถานะจะเคลื่อนจากสถานะหนึ่งไปยังอีกสถานะหนึ่งผ่านการเปลี่ยนสถานะ ฟังก์ชันเปลี่ยนสถานะจะรับสถานะปัจจุบันและเหตุการณ์ แล้วคืนสถานะถัดไป

type State =
  | { status: "idle" }
  | { status: "loading" }
  | { status: "success"; data: string }
  | { status: "error"; message: string };

function start(s: State): State {
  if (s.status === "idle") return { status: "loading" };
  return s;
}
console.log(start({ status: "idle" }).status);

การสร้างแบบจำลองเหตุการณ์ด้วย

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

type Event =
  | { type: "FETCH" }
  | { type: "RESOLVE"; data: string }
  | { type: "REJECT"; message: string };

const e: Event = { type: "RESOLVE", data: "ok" };
console.log(e.type);

ฟังก์ชันเปลี่ยนสถานะฉบับสมบูรณ์

รวมยูเนียนของสถานะและเหตุการณ์ไว้ในตัวลดสถานะเดียว การใช้สวิตช์กับทั้งสองอย่างทำให้การเปลี่ยนสถานะแต่ละรายการชัดเจนและปลอดภัยด้านชนิด

type State =
  | { status: "idle" }
  | { status: "loading" }
  | { status: "success"; data: string }
  | { status: "error"; message: string };
type Event =
  | { type: "FETCH" }
  | { type: "RESOLVE"; data: string }
  | { type: "REJECT"; message: string };

function reduce(s: State, e: Event): State {
  if (e.type === "FETCH") return { status: "loading" };
  if (e.type === "RESOLVE") return { status: "success", data: e.data };
  return { status: "error", message: e.message };
}
console.log(reduce({ status: "idle" }, { type: "FETCH" }).status);

สถานะที่ไม่ถูกต้องไม่สามารถแสดงแทนได้

คุณไม่สามารถมีทั้ง data และ error message ในเวลาเดียวกันได้ การออกแบบด้วยยูเนียนจะห้ามสถานะที่ขัดแย้งกันตั้งแต่ต้น

type State =
  | { status: "success"; data: string }
  | { status: "error"; message: string };

// const bad: State = { status: "success", data: "x", message: "y" };
// Allowed extra props would be flagged in strict object checks.
console.log("no contradictory states");

การป้องกันการเปลี่ยนสถานะที่ไม่ถูกต้อง

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

type State = { status: "idle" } | { status: "loading" };
type Event = { type: "FETCH" } | { type: "CANCEL" };

function reduce(s: State, e: Event): State {
  if (s.status === "loading" && e.type === "CANCEL") return { status: "idle" };
  if (s.status === "idle" && e.type === "FETCH") return { status: "loading" };
  return s; // ignore invalid combos
}
console.log(reduce({ status: "loading" }, { type: "CANCEL" }).status);

การเพิ่มการตรวจสอบครบทุกกรณี

ใช้ตัวลดสถานะร่วมกับ assertNever เพื่อให้การเพิ่มสถานะหรือเหตุการณ์ใหม่แสดงทุกจุดที่คุณต้องแก้ไข

function assertNever(x: never): never { throw new Error("unhandled"); }
type State = { status: "idle" } | { status: "loading" } | { status: "done"; data: string };

function view(s: State): string {
  switch (s.status) {
    case "idle": return "idle";
    case "loading": return "loading";
    case "done": return s.data;
    default: return assertNever(s);
  }
}
console.log(view({ status: "done", data: "ok" }));

สถานะเริ่มต้นและสถานะสุดท้าย

กำหนดสถานะเริ่มต้นที่ชัดเจน (มักเป็น idle) และสถานะสิ้นสุด (success หรือ error) เพื่อบันทึกลำดับอายุการทำงานของเครื่องจักร

type State =
  | { status: "idle" }
  | { status: "loading" }
  | { status: "success"; data: string }
  | { status: "error"; message: string };

const initial: State = { status: "idle" };
console.log("Start:", initial.status);

เครื่องจักรสถานะขนาดเล็กฉบับสมบูรณ์

นี่คือลำดับทั้งหมด: เริ่มจาก idle เปลี่ยนเป็น loading เมื่อดึงข้อมูล และเปลี่ยนเป็น success เมื่อได้ผลลัพธ์ ชนิดต่าง ๆ ช่วยให้ทุกขั้นตอนถูกต้อง

type State = { status: "idle" } | { status: "loading" } | { status: "success"; data: string };
type Event = { type: "FETCH" } | { type: "RESOLVE"; data: string };

function reduce(s: State, e: Event): State {
  if (e.type === "FETCH") return { status: "loading" };
  return { status: "success", data: e.data };
}
let st: State = { status: "idle" };
st = reduce(st, { type: "FETCH" });
st = reduce(st, { type: "RESOLVE", data: "hi" });
console.log(st.status, st.status === "success" ? st.data : "");

ตรวจสอบความเข้าใจ: เครื่องจักรสถานะ

ตรวจสอบความเข้าใจของคุณเกี่ยวกับการสร้างแบบจำลองเครื่องจักรสถานะ

สรุปทบทวน: การสร้างแบบจำลองเครื่องจักรสถานะ

คุณได้สร้างแบบจำลอง idle/loading/success/error เป็นยูเนียนแบบมีตัวจำแนก เขียนการเปลี่ยนสถานะที่ปลอดภัยด้านชนิดบนยูเนียนของสถานะและเหตุการณ์ และใช้การตรวจสอบครบทุกกรณีเพื่อให้เครื่องจักรถูกต้องเมื่อขยายเพิ่มเติม

type State = { status: "idle" } | { status: "loading" } | { status: "success"; data: string };
const s: State = { status: "success", data: "done" };
console.log(s.status === "success" ? s.data : "");

คำถามที่พบบ่อย

บทเรียน “การจำลองเครื่องสถานะ” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “การจำลองเครื่องสถานะ” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส TypeScript Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส TypeScript Academy มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “การจำลองเครื่องสถานะ”

แสดงสถานะที่มีจำนวนจำกัดด้วยยูเนียนแบบจำแนก คุณปฏิบัติ TypeScript Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน TypeScript Academy หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน TypeScript Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน

บทเรียน “การจำลองเครื่องสถานะ” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน TypeScript Academy นี้ได้ไหม

ได้ บทเรียน TypeScript Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. การสร้างยูเนียนแบบจำแนก
  2. การจำกัดชนิดข้อมูลด้วยตัวจำแนก
  3. การตรวจสอบความครอบคลุมทั้งหมดด้วย never
  4. การจำลองเครื่องสถานะ
← กลับไปที่ TypeScript Academy