ความลึกและขีดจำกัดของการเรียกซ้ำ
ทำความเข้าใจข้อจำกัดด้านความลึกของการเรียกซ้ำใน TypeScript
ความลึกและขีดจำกัดของการเรียกซ้ำ เป็นบทเรียน TypeScript Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน TypeScript Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส TypeScript Academy มีบทเรียนทั้งหมด 4 บทเรียน
TypeScript มีขีดจำกัดการเรียกซ้ำ
ชนิดข้อมูลแบบเรียกซ้ำมีประสิทธิภาพสูง แต่ตัวตรวจสอบชนิดข้อมูลจะจำกัดความลึกที่สามารถสร้างอินสแตนซ์ได้ หากถึงขีดจำกัด คุณจะได้รับข้อผิดพลาดด้านความลึก
// Excessively deep recursive types can produce:
// "Type instantiation is excessively deep and possibly infinite."ที่มาของข้อผิดพลาดด้านความลึก
ชนิดข้อมูลแบบมีเงื่อนไขที่เรียกซ้ำโดยไม่มีกรณีฐานที่ชัดเจนและมีขนาดเล็กลง อาจวนซ้ำรุนแรง โดยเฉพาะเมื่อใช้ร่วมกับยูเนียนขนาดใหญ่หรือการสร้างทูเพิล
type Repeat<N extends number, Acc extends unknown[] = []> =
Acc["length"] extends N ? Acc : Repeat<N, [...Acc, unknown]>;
// Large N can exceed the instantiation depth.
type Five = Repeat<5>;การเรียกซ้ำที่จำกัดขอบเขตอย่างปลอดภัย
ทำให้การเรียกซ้ำมีความตื้นและอยู่ภายในขอบเขต การสร้างทูเพิลขนาดเล็กทำได้อย่างปลอดภัย โดยกรณีฐาน Acc["length"] extends N จะหยุดการเรียกซ้ำได้อย่างรวดเร็ว
type Tuple<N extends number, Acc extends unknown[] = []> =
Acc["length"] extends N ? Acc : Tuple<N, [...Acc, unknown]>;
type Three = Tuple<3>; // [unknown, unknown, unknown]
const t: Three = [1, 2, 3];
console.log(t.length);รูปแบบชนิดข้อมูลแบบเรียกซ้ำหาง
TypeScript ปรับปรุงประสิทธิภาพของชนิดข้อมูลแบบมีเงื่อนไขที่เรียกซ้ำแบบหางบางรูปแบบด้วยการส่งต่อตัวสะสม ทำให้เรียกซ้ำได้ลึกกว่าการซ้อนกันแบบพื้นฐาน
type Reverse<T extends unknown[], Acc extends unknown[] = []> =
T extends [infer Head, ...infer Tail]
? Reverse<Tail, [Head, ...Acc]>
: Acc;
type R = Reverse<[1, 2, 3]>; // [3, 2, 1]
const r: R = [3, 2, 1];
console.log(r);เหตุผลที่ตัวสะสมช่วยได้
การส่งผลลัพธ์ต่อไปในตัวสะสมจะทำให้การเรียกซ้ำอยู่ในตำแหน่งหาง ซึ่ง TypeScript สามารถคลี่การเรียกซ้ำได้อย่างมีประสิทธิภาพมากกว่าชนิดข้อมูลแบบมีเงื่อนไขที่ซ้อนกันลึก
type Join<T extends string[], Acc extends string = ""> =
T extends [infer H extends string, ...infer R extends string[]]
? Join<R, Acc extends "" ? H : Acc>
: Acc;
type First = Join<["a", "b", "c"]>; // "a"
const f: First = "a";
console.log(f);การหลีกเลี่ยงการเรียกซ้ำที่ไม่ใช่แบบหาง
การห่อการเรียกซ้ำไว้ภายในการดำเนินการชนิดข้อมูลอื่นจะทำลายตำแหน่งหางและอาจทำให้ถึงขีดจำกัดเร็วขึ้น ควรส่งต่อสถานะในตัวสะสมแทน
// Non-tail (can be costly): builds nesting around the recursive call
// type Bad<T> = T extends [infer H, ...infer R] ? [H, ...Bad<R>] : [];
// Tail-friendly alternative uses an accumulator parameter.
console.log("prefer accumulators");การกำหนดขีดจำกัดความลึกอย่างชัดเจน
เพิ่มตัวนับความลึกเพื่อให้ชนิดข้อมูลหยุดทำงานหลังจากถึงจำนวนระดับที่กำหนด โดยแลกความครอบคลุมกับการสิ้นสุดการทำงานที่รับประกันได้
type Flatten<T, Depth extends unknown[] = []> =
Depth["length"] extends 5
? T
: T extends (infer U)[]
? Flatten<U, [...Depth, unknown]>
: T;
type X = Flatten<number[][]>; // number
const x: X = 7;
console.log(x);โดยทั่วไปความลึกจริงไม่เป็นปัญหา
ชนิดข้อมูลแบบเรียกซ้ำที่ใช้ในชีวิตประจำวัน เช่น รายการเชื่อมโยง ต้นไม้ และเจสัน แทบไม่เคยถึงขีดจำกัด เพราะข้อมูลที่คุณสร้างอินสแตนซ์นั้นมีความตื้น ขีดจำกัดนี้ส่งผลหลักต่อการคำนวณระดับชนิดข้อมูลที่ซับซ้อน
type Json = string | number | boolean | null | Json[] | { [k: string]: Json };
const v: Json = { a: { b: { c: 1 } } }; // fine, shallow
console.log(v);การสังเกตข้อความข้อผิดพลาด
เมื่อพบข้อความว่า "ลึกเกินไปและอาจไม่สิ้นสุด" ให้ตรวจหากรณีฐานที่หายไป ตัวสะสมที่อยู่ในตำแหน่งซึ่งไม่ใช่หาง หรือข้อมูลขาเข้าที่มีขนาดใหญ่เกินไป
// Fixes: add/tighten the base case, switch to tail recursion,
// reduce input size, or cap with a depth counter.
console.log("check base case and tail position");การเรียกซ้ำขณะทำงานเป็นคนละเรื่องกัน
ขีดจำกัดเหล่านี้เกี่ยวข้องกับการเรียกซ้ำในระดับชนิดข้อมูล ฟังก์ชันแบบเรียกซ้ำทั่วไปที่ทำงานกับชนิดข้อมูลแบบเรียกซ้ำจะทำงานขณะรันไทม์ และมีขีดจำกัดเฉพาะจากสแตกการเรียกใช้
type TreeNode<T> = { value: T; children: TreeNode<T>[] };
function count<T>(n: TreeNode<T>): number {
return 1 + n.children.reduce((a, c) => a + count(c), 0);
}
console.log(count({ value: 1, children: [{ value: 2, children: [] }] }));การออกแบบภายใต้ขีดจำกัด
ควรเลือกใช้ข้อมูลที่มีความตื้น รูปแบบการเรียกซ้ำแบบหางร่วมกับตัวสะสม และการจำกัดความลึกอย่างชัดเจน ด้วยแนวทางเหล่านี้ คุณแทบไม่พบขีดจำกัดดังกล่าวในโค้ดจริง
type Length<T extends unknown[]> = T["length"];
type N = Length<[1, 2, 3]>; // 3
const n: N = 3;
console.log(n);ตรวจสอบความเข้าใจอย่างรวดเร็ว: ขีดจำกัดการเรียกซ้ำ
ทดสอบความเข้าใจเกี่ยวกับความลึกและขีดจำกัดของการเรียกซ้ำ
สรุป: ความลึกและขีดจำกัดของการเรียกซ้ำ
คุณเรียนรู้ว่า TypeScript จำกัดความลึกของการเรียกซ้ำในระดับชนิดข้อมูล รูปแบบการเรียกซ้ำแบบหางที่ใช้ตัวสะสมและการจำกัดความลึกอย่างชัดเจนช่วยได้ และข้อมูลแบบเรียกซ้ำที่ใช้ทั่วไปแทบไม่ถึงขีดจำกัด
type Reverse<T extends unknown[], Acc extends unknown[] = []> =
T extends [infer H, ...infer R] ? Reverse<R, [H, ...Acc]> : Acc;
const r: Reverse<[1, 2]> = [2, 1];
console.log(r);คำถามที่พบบ่อย
บทเรียน “ความลึกและขีดจำกัดของการเรียกซ้ำ” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “ความลึกและขีดจำกัดของการเรียกซ้ำ” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส TypeScript Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส TypeScript Academy มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “ความลึกและขีดจำกัดของการเรียกซ้ำ”
ทำความเข้าใจข้อจำกัดด้านความลึกของการเรียกซ้ำใน TypeScript คุณปฏิบัติ TypeScript Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน TypeScript Academy หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน TypeScript Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน
บทเรียน “ความลึกและขีดจำกัดของการเรียกซ้ำ” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน TypeScript Academy นี้ได้ไหม
ได้ บทเรียน TypeScript Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- การกำหนดชนิดข้อมูลแบบเรียกซ้ำ
- การกำหนดชนิดข้อมูลให้โครงสร้างต้นไม้
- ชนิดข้อมูลค่า JSON
- ความลึกและขีดจำกัดของการเรียกซ้ำ