type HttpMethod = "GET" | "POST" | "PUT" | "DELETE";
type Route = {
path: string;
method: HttpMethod;
};
// ❌ widening が起こる
const routes1: Record<string, Route> = {
getUser: { path: "/users/:id", method: "GET" },
createUser: { path: "/users", method: "POST" },
};
routes1.getUser.method // 型: HttpMethod (Union型)
// 関数で使おうとすると...
function handleRequest(method: "GET" | "POST") {
// ...
}
handleRequest(routes1.getUser.method); // ❌ エラー!
// HttpMethod 型は "GET" | "POST" | "PUT" | "DELETE" なので代入できない
// ✅ widening を抑止
const routes2 = {
getUser: { path: "/users/:id", method: "GET" },
createUser: { path: "/users", method: "POST" },
} as const satisfies Record<string, Route>;
routes2.getUser.method // 型: "GET" (リテラル型)
handleRequest(routes2.getUser.method); // ✅ OK!
// 型 "GET" | "POST" を
// 型 Extract<HttpMethod,"GET" | "POST"> にするだけで ✅OK
function handleRequest(method: Extract<HttpMethod,"GET" | "POST">) {
// ...
}
type Config = { apiUrl: string; timeout: number; features: {
analytics: boolean;
darkMode: boolean;
}; };
// ❌ これはダメ(型チェックされない) const config1 = { apiUrl: "https://api.example.com", timeout: 3000, features: {
analytics: true,
darkMood: true, // ← typo! でもエラーにならない
}, } as const;
// ❌ これもダメ(readonlyにならない) const config2: Config = { apiUrl: "https://api.example.com", timeout: 3000, features: {
analytics: true,
darkMode: true,
}, }; config2.timeout = 5000; // ✅ 変更できてしまう
// ✅ readonly + 型チェック const config3 = { apiUrl: "https://api.example.com", timeout: 3000, features: {
analytics: true,
darkMood: true, // ❌ エラー! typoが検出される
}, } as const satisfies Config;
config3.timeout = 5000; // ❌ エラー! readonlyなので変更できない