ข้ามไปยังเนื้อหา

Functions

function type อธิบาย parameter และ return type เขียน inline หรือเป็น named type ก็ได้:

type BinaryOp = (a: number, b: number) => number;
const add: BinaryOp = (a, b) => a + b;
// a และ b ถูก infer เป็น number จาก context — ไม่ต้อง annotate

parameter รองรับ optional (?), default value และ rest:

function make(name: string, count = 1, ...tags: string[]): void {
// count default เป็น 1; tags เก็บที่เหลือเข้า string[]
}

optional parameter x?: number เป็น number | undefined; defaulted parameter count = 1 มองจากฝั่งภายในเป็น number เฉย ๆ แต่ผู้เรียกละไว้ได้

overload ให้ function หนึ่งตัวแสดง call signature หลายแบบ เขียน signature หลายบรรทัดตามด้วย implementation หนึ่งอัน:

function len(x: string): number;
function len(x: unknown[]): number;
function len(x: string | unknown[]): number {
return x.length;
}
len("hi"); // ✅ 2
len([1, 2, 3]); // ✅ 3

overload ทรงพลังแต่ใช้เกินง่าย เมื่อ signature ต่างกันแค่ที่ type ของ parameter — ไม่ใช่ที่ ความสัมพันธ์ ระหว่าง parameter กับ return — union parameter ตัวเดียวเรียบง่ายและชัดกว่า:

// เรียบง่ายกว่า overload สองตัว:
function len(x: string | unknown[]): number {
return x.length;
}

หยิบ overload จริง ๆ มาใช้เฉพาะเมื่อ return type ขึ้นกับ input shape ที่รับเข้ามาในแบบที่ union แสดงไม่ได้

ใน standalone function this type ได้ด้วย parameter ตัวแรกพิเศษที่ หายไปที่ call site (เป็น compile-time เท่านั้น):

interface Button { label: string; }
function handleClick(this: Button, event: Event): void {
console.log(this.label); // this เป็น Button
}

ช่วยจับบั๊กคลาสสิกที่ method เสีย this เมื่อถูกส่งเป็น callback เปล่า ๆ มีประโยชน์สุดกับ API แบบเก่าที่พึ่ง this; กับ arrow function และ pattern สมัยใหม่คุณจะใช้น้อยลง

function type ที่ return void ไม่ได้ แปลว่า “function ต้องไม่ return อะไร” แต่แปลว่า “ผู้เรียกจะเมิน return value” function ที่ return อะไรบางอย่างจึงยัง assign ให้ type ที่ return void ได้:

type Callback = () => void;
const cb: Callback = () => 42; // ✅ ได้! ค่า 42 แค่ถูกเมิน
flowchart LR
  fn["() => number
(returns 42)"] -->|assignable to| target["() => void
(caller ignores return)"]
  target --> use["callers treat result
as void — safe"]
void แปลว่า return ถูกเมิน ไม่ใช่ห้าม return

นี่แหละคือเหตุผลว่าทำไม array.forEach(x => arr.push(x)) ถึง type-check ผ่านทั้งที่ push return number: forEach ต้องการ callback แบบ void และเมินสิ่งที่ return กลับมา พอรู้กฎแล้วก็เลิกลึกลับ — แต่แทบทุกคนต้องงงกับเรื่องนี้ก่อน

ควรใช้ overload แทน union parameter ตัวเดียวเมื่อไร?
`this` parameter (`function f(this: T, ...)`) ทำอะไรที่ call site?
`const cb: () => void = () => 42` ทำได้ไหม?
ทำไม `arr.forEach(x => other.push(x))` ถึง type-check ผ่านทั้งที่ push return number?