ค่าที่ตรวจสอบใน TypeScript ยังคงถูกทำเครื่องหมายว่าเป็น undefined ในตัวฟังก์ชัน
มีการตรวจสอบ if บน var1 และสิ่งนี้ทำงานตามที่คาดไว้ ยกเว้นตัวฟังก์ชันภายในคำสั่ง if ไม่ชัดเจนว่าเพราะอะไร
let var1: number | undefined;
let var2: number;
if (var1) {
var2 = var1;
const func = () => {
var2 = var1;
};
func();
console.log(var2);
}
คำตอบ #1
คำตอบมาตรฐานสำหรับคำถามนี้สามารถพบได้ที่ microsoft/TypeScript#9998
โดยทั่วไป จะมีค่าใช้จ่ายสูงเกินไปสำหรับคอมไพเลอร์ในการทำการวิเคราะห์การไหลของการควบคุมที่ถูกต้องครบถ้วนซึ่งข้ามขอบเขตของฟังก์ชั่น ฟังก์ชั่นสามารถถูกเรียกซ้ำหลายครั้งจากหลายตำแหน่ง วิธีเดียวที่สิ่งนี้จะทำงานได้คือคอมไพเลอร์ต้องทำการแทรกโค้ดของฟังก์ชั่นทุกครั้งที่เรียก สำหรับกรณีที่ง่ายมากเช่นโค้ดตัวอย่างของคุณ เป็นไปได้ที่คอมไพเลอร์อาจวิเคราะห์ประเภทโดยเริ่มจากการแปลงมันเป็นบางอย่างเช่น:
if (var1) {
var2 = var1;
// replace func() with its body
{
var2 = var1;
}
console.log(var2);
}
แต่การทำเช่นนี้ตลอดเวลา "คงไม่ใช่เรื่องที่ปฏิบัติได้แม้แต่น้อย" ตามที่กล่าวไว้ใน microsoft/TypeScript#9998 แทนที่นั้น ตัวคอมไพเลอร์ต้องใช้ทางลัดเพื่อให้ทำงานได้มีประสิทธิภาพ และทางลัดเหล่านั้นมักจะทำให้เกิดผลลบเท็จ (ไม่มีการรายงานข้อผิดพลาดแม้ว่าจะมีปัญหาจริง) ผลบวกเท็จ (รายงานข้อผิดพลาดแม้ว่าไม่มีปัญหาจริง) หรือทั้งสองอย่าง
คอมไพเลอร์ TypeScript ในปัจจุบันจะสมมติอย่างมองโลกในแง่ดีว่าการเรียกฟังก์ชันไม่มีผลต่อการวิเคราะห์การไหลของการควบคุม ส่งผลให้เกิดผลลบเท็จ:
if (var1) {
const func = () => (var1 = undefined);
func();
var2 = var1; // no error, but there should be
}
และสมมติอย่างเชิงลบว่าไม่มีการจำกัดลงภายในร่างกายของฟังก์ชัน ซึ่งนำไปสู่ผลบวกเทียม เช่นเดียวกับในตัวอย่างโค้ดของคุณ:
if (var1) {
const func = () => {
var2 = var1; // error, but there shouldn't be
};
func();
}
มีการอภิปรายใน microsoft/TypeScript#9998 เกี่ยวกับแนวทางที่เป็นไปได้ต่าง ๆ และว่าพวกมันนำไปสู่ปัญหาในสถานการณ์อื่น ๆ อย่างไร สำหรับตอนนี้ สิ่งนี้ก็เป็นเพียงสิ่งที่เป็นอยู่
แล้ววิธีแก้ปัญหาที่นี่คืออะไร? ชัดเจนว่าคุณสามารถทำการ inline func() ด้วยตัวเอง อีกวิธีหนึ่งคือการเลี่ยงปัญหาโดยการบันทึกค่าที่ถูกจำกัดประเภทแล้ว var1 ลงในตัวแปรใหม่ (เช่น var1Saved) ซึ่งคอมไพเลอร์จะสรุปให้มีประเภทจำกัดตามค่าที่เริ่มต้นด้วย ประเภทดังกล่าวจะไม่สามารถขยายประเภทได้ ดังนั้นมันจะถูกมองว่าเป็น number เสมอและจะไม่เคยเป็น number | undefined แม้กระทั่งใน func():
if (var1) {
const var1Saved = var1;
const func = () => {
var2 = var1Saved; // okay
};
func();
}
นั่นใช้ได้กับกรณีนี้ แต่ในหลายกรณีคุณจะพบว่าฟังก์ชันที่ปิดตัวแปรหรือคุณสมบัติที่ประเภทอาจถูกจำกัดโดยการวิเคราะห์โฟลว์การควบคุมมักจะมีปัญหาเช่นนี้ที่คอมไพเลอร์ไม่รู้ว่าประเภทจริงของตัวแปรเหล่านี้จะเป็นอะไร และวิธีทั่วไปเพียงวิธีเดียวในการจัดการกับเรื่องนี้คือการใช้การรับรองประเภทซึ่งคุณบอกคอมไพเลอร์เกี่ยวกับข้อมูลที่มันไม่สามารถหาคำตอบได้เอง และรับผิดชอบต่อความถูกต้องของการรับรองดังกล่าว:
if (var1) {
const func = () => {
var2 = var1 as number; // okay
};
func();
}
ลิงก์ Playground ไปยังโค้ด
คำตอบ #2
let var1: number | undefined
let var2: number | undefined
if (var1) {
var2 = var1;
const func = () => {
var2 = var1;
}
func();
console.log(var2)
}
เมื่อค่าของ var2 รับค่าของ var1 หมายความว่าในบางจุดมันอาจไม่ถูกกำหนด ดังนั้นคุณจึงหลีกเลี่ยงปัญหาประเภทนี้

