ค้นหาเว็บไซต์

typescript - วิธีประกาศชนิดของฟังก์ชัน const `f=({ a=0 }={}) => a` ใน TS


ฉันใช้การระบุประเภทใน TS เป็นเหมือนเอกสารประกอบ สำหรับฉัน มันเป็นเรื่องดีที่จะรู้ว่าฟังก์ชันของฉันจะจัดการประเภทใดบ้างตั้งแต่ต้น

ฉันยังหาแนวทางในการประกาศชนิดของฟังก์ชันประเภทนี้ไม่ได้ คอมไพเลอร์จะสรุปชนิดเอง แต่เมื่อฉันพยายามกำหนดหมายเหตุด้วยชนิดเดียวกันเอง มันก็ล่ม

ยกตัวอย่างฟังก์ชันนี้:

// compiler infers the type
// f: ({ a }?: { a?: number | undefined }) => number
const f = ({ a = 0 } = {}) => a;

แต่เมื่อฉันพยายามทำหมายเหตุ มันล้มเหลวพร้อมข้อผิดพลาดดังต่อไปนี้

const f: ({ a }?: { a?: number | undefined }) => number =
    ({ a = 0 } = {}) => a;
//     ^
//     \-- Property 'a' does not exist on type '{ a?: number | undefined; } | undefined'

คำตอบ #1

มันดูเหมือนเป็นบั๊กในคอมไพเลอร์ หรืออย่างน้อยก็เป็นข้อจำกัดที่น่าเสียดาย ผมยังไม่พบปัญหาที่มีอยู่ใน GitHub เกี่ยวกับสถานการณ์เฉพาะนี้ microsoft/TypeScript#35160 ดูเหมือนจะเกี่ยวข้อง แต่ก็ไม่ได้ตอบว่าเหตุการณ์แบบนี้เกิดขึ้นได้อย่างไร ผมได้ยื่น microsoft/TypeScript#37271 เพื่อหาข้อมูลว่ากำลังเกิดอะไรขึ้น; ผมจะแจ้งที่นี่ถ้าผมได้รับข้อมูลเพิ่มเติม

อัปเดต: นี่คือบั๊กของคอมไพเลอร์ที่ถูกแก้ไขใน typescript@next และจะถูกปล่อยใน TypeScript 3.9.1 เมื่อถูกปล่อยแล้ว คำตอบที่นี่ก็จะเป็นแค่ "อัปเดตเวอร์ชัน TS ของคุณ" สำหรับเวอร์ชันก่อนหน้าและสำหรับผู้สนใจอื่น ๆ ส่วนที่เหลือของคำตอบยังคงเหมือนเดิม

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

const f = ({ a = 0 } = {}) => a;

const g: ({ a }?: { a?: number; }) => number = f; // no error

นั่นใช้ได้ ดังนั้นปัญหาต้องอยู่ที่เมื่อคุณระบุชนิดของ f อย่างชัดเจน มันจะให้ชนิดตามบริบทสำหรับพารามิเตอร์ ซึ่งคอมไพเลอร์ไม่พอใจด้วยเหตุผลบางอย่าง (ซึ่งอาจจะเป็นบั๊ก) วิธีแก้ปัญหาที่ผมนึกได้คือระบุชนิดของพารามิเตอร์นี้อย่างชัดเจน:

const h: ({ a }?: { a?: number }) => number =
  ({ a = 0 }: { a?: number } = {}) => a; // no error

นั่นก็ใช้ได้ มันแปลกที่คุณต้องระบุชนิดทั้งฟังก์ชันลูกศรและพารามิเตอร์ของมัน แต่ก็ยังดีที่คุณมีแนวทางไปข้างหน้า หวังว่าจะช่วยได้ โชคดี!

ลิงก์ Playground ไปยังโค้ด

คำตอบ #2

ถ้าฉันเข้าใจสิ่งที่คุณพูดถูกต้อง คุณควรสามารถแทนที่ { a } ด้วยชื่อผันแปรที่คุณเลือกได้:

const f: (v?: {a?: number | undefined}) => number = ({ a = 0 } = {}) => a;

เพราะคุณกำลังอธิบายรูปร่างของอาร์กิวเมนต์ในคำอธิบายประกอบ คุณไม่จำเป็นต้องระบุว่า a เป็นสมาชิกในประกาศพารามิเตอร์