Dark mode
let username: string = "john"; username = 123; // Type Error: Cannot assign number to string
ประโยชน์ของ Static Typing:
- จับข้อผิดพลาดตั้งแต่ยังไม่รันโปรแกรม
- ช่วยให้ IDE แนะนำการใช้งานได้ถูกต้อง
- ทำให้โค้ดอ่านง่ายขึ้น
Type Inference (การอนุมาน type)
เคล็ดลับ
ควรใช้ type inference เมื่อค่าเริ่มต้นชัดเจน แต่ควรระบุ type ชัดเจนเมื่อรับค่าจาก API หรือเมื่อต้องการความชัดเจน
TypeScript สามารถเดา type ได้โดยอัตโนมัติจากค่าที่กำหนด
ts
let message = "Hello"; // TypeScript รู้ว่าเป็น string
let count = 10; // รู้ว่าเป็น number
Structural Typing (ระบบ type แบบโครงสร้าง)
ข้อควรระวัง
Object ที่มี property มากกว่าที่ interface กำหนดจะใช้งานได้ แต่ถ้ามี property น้อยกว่าจะเกิด error ทันที
ตรวจสอบความเข้ากันได้ของ type จากโครงสร้าง ไม่ใช่จากชื่อ type
ts
interface Product {
id: number;
name: string;
price: number;
}
function displayProductInfo(product: Product) {
console.log(`${product.name}: $${product.price}`);
}
// ตัวอย่างที่ 1: ใช้งานได้ตามปกติ
const laptop = {
id: 1,
name: "MacBook Pro",
price: 1999,
};
displayProductInfo(laptop); // ทำงานได้ปกติ
// ตัวอย่างที่ 2: เกิด error เพราะขาด property ที่จำเป็น
const invalidProduct = {
id: 2,
name: "iPhone",
};
// @ts-expect-error: Argument of type '{ id: number; name: string; }' is not assignable to parameter of type 'Product'.
displayProductInfo(invalidProduct);
// ตัวอย่างที่ 3: เกิด error เมื่อพยายามใช้ object literal โดยตรง
// @ts-expect-error: Argument of type '{ id: number; name: string; }' is not assignable to parameter of type 'Product'.
displayProductInfo({
id: 3,
name: "iPad",
});
Type Checking (การตรวจสอบ type)
วิธีการตรวจสอบ | รูปแบบการใช้งาน | ตัวอย่างการใช้ |
---|---|---|
Type Predicates | function isType(value): value is Type | function isString(value: unknown): value is string |
typeof operator | typeof value === "type" | if (typeof x === "string") |
Type Guards (การป้องกัน type)
Type Guard | วิธีใช้ | ตัวอย่างการใช้ | ใช้กับ |
---|---|---|---|
instanceof | ตรวจสอบ instance ของ class | if (error instanceof Error) | Class |
in operator | ตรวจสอบว่ามี property ใน object หรือไม่ | if ("id" in user) | Object types |
Custom Type Guard | สร้างฟังก์ชันตรวจสอบ type เอง | function isFish(pet: Fish | Bird): pet is Fish | ทุก type |
Equality Narrowing | ใช้การเปรียบเทียบค่า | if (x === null) | ทุก type |
Discriminated Union | ใช้ property ร่วมเพื่อแยก type | if (shape.kind === "circle") | Union types |
Type Casting (การแปลง type)
วิธีการ | รูปแบบ syntax | ตัวอย่างการใช้ |
---|---|---|
as syntax | value as TargetType | (input as string).toUpperCase() |
angle-bracket syntax | <TargetType>value | <string>input.toUpperCase() |
Type Assertion (การยืนยัน type)
เทคนิคการบอก TypeScript ว่าเรารู้ type ของค่าที่แน่นอน (ใช้เมื่อเรารู้ว่า type จริงคืออะไร แต่ TypeScript ไม่สามารถอนุมานได้)
รูปแบบ | คำอธิบาย | ตัวอย่างการใช้งาน |
---|---|---|
as syntax | รูปแบบมาตรฐานที่แนะนำ | const length = (input as string).length |
Angle-bracket syntax | รูปแบบเก่า (ไม่แนะนำใน TSX) | const length = (<string>input).length |
const assertion | ระบุว่าเป็นค่าคงที่ | let colors = ['red', 'green'] as const |
Non-null assertion | ยืนยันว่าไม่ใช่ null/undefined | document.getElementById('root')! |
ข้อควรระวัง
ควรใช้ Type Assertion เท่าที่จำเป็น เพราะอาจทำให้การตรวจสอบ type ไม่ทำงานตามที่คาดหวัง
ts
// ตัวอย่าง as syntax
const input: unknown = "hello";
const length = (input as string).length;
// ตัวอย่าง const assertion
const colors = ["red", "green"] as const;
// colors.push("blue"); // Error: Property 'push' does not exist
// ตัวอย่าง non-null assertion
function getElement(id: string) {
return document.getElementById(id)!; // ยืนยันว่าจะไม่เป็น null
}
เมื่อไหร่ควรใช้ Type Assertion
- เมื่อทำงานกับ DOM และรู้แน่ชัดว่า element มีอยู่
- เมื่อรับค่าจาก external source (เช่น API) และรู้ structure ชัดเจน
- เมื่อต้องการเปลี่ยน type ชั่วคราวสำหรับการทำงานบางอย่าง
Type Guard (การตรวจสอบ type ขณะ runtime)
เทคนิคตรวจสอบ type ขณะ runtime เพื่อให้ TypeScript รู้ type ที่แท้จริง
Type Guard | วิธีใช้ | ตัวอย่างการใช้ | ใช้กับ |
---|---|---|---|
typeof | ตรวจสอบ type พื้นฐาน | if (typeof x === "string") | string, number, boolean, symbol, etc. |
instanceof | ตรวจสอบ instance ของ class | if (error instanceof Error) | Class |
in | ตรวจสอบว่ามี property ใน object หรือไม่ | if ("id" in user) | Object types |
Custom Type Guard | สร้างฟังก์ชันตรวจสอบ type เอง | function isFish(pet: Fish | Bird): pet is Fish | ทุก type |
Equality Narrowing | ใช้การเปรียบเทียบค่า | if (x === null) | ทุก type |
Discriminated Union | ใช้ property ร่วมเพื่อแยก type | if (shape.kind === "circle") | Union types |
Custom Type Guard
การสร้างฟังก์ชันตรวจสอบ type ด้วยตัวเอง โดยใช้ "type predicate" (คืนค่าเป็น parameterName is Type
)
ts
interface Fish {
swim(): void;
}
interface Bird {
fly(): void;
}
// Custom Type Guard
function isFish(pet: Fish | Bird): pet is Fish {
return (pet as Fish).swim !== undefined;
}
// ตัวอย่างการใช้งาน
function move(pet: Fish | Bird) {
if (isFish(pet)) {
pet.swim(); // TypeScript รู้ว่า pet เป็น Fish
} else {
pet.fly(); // TypeScript รู้ว่า pet เป็น Bird
}
}
Equality Narrowing
ใช้การเปรียบเทียบค่า (===
, !==
, ==
, !=
) เพื่อตรวจสอบ type
ts
function printAll(strs: string | string[] | null) {
if (strs !== null) {
if (typeof strs === "object") {
for (const s of strs) { // strs เป็น string[]
console.log(s);
}
} else if (typeof strs === "string") {
console.log(strs); // strs เป็น string
}
}
}
เมื่อไหร่ควรใช้ Type Guard
- เมื่อต้องการตรวจสอบ type ขณะ runtime
- เมื่อทำงานกับ union types
- เมื่อต้องการให้ TypeScript รู้ type ที่แท้จริงใน scope นั้นๆ
ตัวอย่างการใช้งานจริง (Modern Examples)
1. Type Inference กับ React Hooks (ใช้งานบ่อย)
ts
// useState จะอนุมาน type อัตโนมัติจากค่าเริ่มต้น
const [count, setCount] = useState(0); // number
const [user, setUser] = useState(null); // User | null
// ระบุ type ชัดเจนเมื่อค่าเริ่มต้นเป็น null
const [data, setData] = useState<ApiResponse | null>(null);
2. Type Guards กับการตรวจสอบ API Response
ts
// ตรวจสอบโครงสร้างข้อมูลจาก API
function isApiSuccess(response: unknown): response is { data: any } {
return !!response && typeof response === "object" && "data" in response;
}
// ใช้งาน
const response = await fetchAPI();
if (isApiSuccess(response)) {
console.log(response.data); // ปลอดภัย
}
3. Discriminated Union กับ Redux Actions
ts
type Action =
| { type: "ADD_TODO"; payload: string }
| { type: "TOGGLE_TODO"; id: number }
| { type: "DELETE_TODO"; id: number };
function reducer(state: State, action: Action) {
switch (action.type) {
case "ADD_TODO":
return [...state, { text: action.payload }];
case "TOGGLE_TODO":
// action.id เข้าถึงได้เฉพาะ case นี้
return state.map(todo =>
todo.id === action.id ? { ...todo, done: !todo.done } : todo
);
// ...
}
}
4. Type Assertion กับ DOM Elements (ใช้เมื่อมั่นใจ)
ts
// ใน React/Next.js
const videoRef = useRef<HTMLVideoElement>(null);
// ใช้งาน
videoRef.current!.play(); // ! สำหรับ non-null assertion