TYPESCRIPT CORE · 94
Function Types 與 Generics:描述「型別之間的關係」
Generic 不是看起來很進階的尖括號。它真正用途是:某個 function 可以處理多種型別,但 input / output 之間仍有必須保持的關係。
Learning outcomes
- 能讀 function parameter / return type contract。
- 能替 callback 寫出正確 function type。
- 能解釋 generic type parameter 代表的「未知但一致」型別。
- 能使用 constraint 保留必要 capability。
1. Function type 是 contract
function formatScore(score: number): string {
return score.toFixed(1);
}
caller 必須提供 number;function 保證回 string。這個 contract 會一路傳到呼叫端。
2. Callback 也有 type
type CourseMapper =
(course: Course) => string;
function mapCourses(
courses: Course[],
mapper: CourseMapper
): string[] {
return courses.map(mapper);
}
TypeScript 不只是檢查「這是不是 function」,還能檢查 callback input / output 是否符合需求。
3. Generic:未知,但不是 any
function first<T>(
items: T[]
): T | undefined {
return items[0];
}
const n = first([1, 2, 3]);
// T = number
const c = first([
{ id: 1, title: "JS", score: 90 }
]);
// T = Course-like object
關鍵:
T 不是「隨便什麼都可以然後不檢查」,而是「呼叫這次決定了一個型別,input/output 都要保持這個關係」。4. Constraint:generic 仍可要求最低能力
function findById<T extends { id: number }>(
items: T[],
id: number
): T | undefined {
return items.find(item => item.id === id);
}
任何 T 都可以,只要至少有 number 型別的 id。
5. Generic Result:統一 success / error contract
type Result<T> =
| { ok: true; data: T }
| { ok: false; error: string };
function success<T>(data: T): Result<T> {
return { ok: true, data };
}
這比 any 好,因為成功時 data 的具體型別會一路保留下來。
6. Project checkpoint:Typed Course API Client v4
type Result<T> =
| { ok: true; data: T }
| { ok: false; error: string };
async function requestJson<T>(
url: string,
validate: (value: unknown) => value is T
): Promise<Result<T>> {
try {
const response = await fetch(url);
if (!response.ok) {
return {
ok: false,
error: "HTTP " + response.status
};
}
const raw: unknown = await response.json();
if (!validate(raw)) {
return {
ok: false,
error: "Invalid payload"
};
}
return {
ok: true,
data: raw
};
} catch {
return {
ok: false,
error: "Network failure"
};
}
}
這裡 generic 沒有取代 validation;它把「validator 通過後,Result 裡的 data 就是 T」這個關係表達出來。
Knowledge check
first<T>和回傳any的差別是什麼?- 為什麼
findById要 constraint? - 替
requestJson寫一個isCourseArrayvalidator。 - 說明 generic 與 runtime validation 各自負責哪一層。