Typescript Advance Use Cases
Some use cases of how those type helps.
Conditions API
Output the regarding type for user input type (Using HTTP standards as example)
type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE';
type ApiOptions =
| { method: "GET"; body?: undefined }
| { method: Exclude<HttpMethod, "GET">; body: Record<string, any> };
function fetchApi(
url: string,
options: ApiOptions
) { /* ... */ }
// β
OK: GET without body
fetchApi('https://api.com', { method: "GET" });
// β
OK: GET with explicit undefined (still allowed)
fetchApi('https://api.com', { method: 'GET', body: undefined });
// β
OK: POST with body
fetchApi('https://api.com', { method: 'POST', body: { id: 1 } });
// β WRONG: Property 'body' is missing...
fetchApi('https://api.com', { method: 'POST' });
// β WRONG: Type '{ id: number; }' is not assignable to type 'undefined'.
fetchApi('https://api.com', { method: 'GET', body: { id: 1 } });Type value filter
Assume we have a fixed object like this, and we want GET only records
type AppRouteMap = {
"/users/dummyTest": "GET";
"/users/checkAvaiableUser": "POST";
"/files/uploadSignatureTest": "POST";
"/files/uploadDocsTest": "POST";
"/testing/dummyTest": "GET";
}
type OnlyGetRoutes = {
[K in keyof AppRouteMap as AppRouteMap[K] extends "GET" ? K : never]: AppRouteMap[K]
};
// type OnlyGetRoutes = {
// "/users/dummyTest": "GET";
// "/testing/dummyTest": "GET";
// }
export type RoutersPathLessStrictOnlyGet = `${keyof OnlyGetRoutes}${string}`;
// type RoutersPathLessStrictOnlyGet = `/users/dummyTest${string}` | `/testing/dummyTest${string}`This time we keep keys that start with β/files/β:
type FilesOnly = {
[K in keyof AppRouteMap as K extends `/files/${string}` ? K : never]: AppRouteMap[K]
};
// {
// "/files/uploadSignatureTest": "POST";
// "/files/uploadDocsTest": "POST";
// }Type reminder for function params
Assume you have a const object, and you are going to require users to input related names and reminder the regarding array items.
const contactList = {
"Peter": ["123", "A1"],
"May": ["345", "B2"],
"Tom": ["567", "C3"],
} as const
// "Peter" | "May" | "Tom"
type Names = keyof typeof contactList
function getNames<
K extends Names,
// When a name match, it will refer to the record list for the value
N extends typeof contactList[K][number]
>(
key: K,
number: N
) {
return `${key}: ${number}`
}
// β
OK
getNames("May", "345")
getNames("Tom", "C3")
// β WRONG
getNames("Peter", "999")
// Argument of type '"999"' is not assignable to parameter of type '"123" | "A1"'.
// Argument of type '"Ken"' is not assignable to parameter of type '"Peter" | "May" | "Tom"'.ts(2345)
getNames("Ken", "B2")Type reminder for objects
When you are require to have several conditions of what key value will refer to what objects (For type reminder):
interface Student {
name: string;
age: number;
}
interface CsStudents extends Student {
major: 'cs';
mainSkill: "Python" | "C++" | "Javascript"
loveToCode: boolean
}
interface PhyStudents extends Student {
major: 'phy';
mainSkill: "Force" | "Electron"
}
interface MathStudents extends Student {
major: 'math';
mainSkill: "d/dx" | "stats" | "intergrations"
}
export type UniversityStudent =
| CsStudents
| PhyStudents
| MathStudents
export const studentList : UniversityStudent[] = [
// [β
OK]: When the major is "cs", the mainSkill will refer to "Python" | "C++" | "Javascript"
{ name: "Tom", age: 21, major: "cs", mainSkill: "Javascript", loveToCode: true },
// [β
OK]: Will auto refer to "PhyStudents" for major is phy
{ name: "Peter", age: 20, major: "phy", mainSkill: "Force"},
// [β WRONG]: Types of property 'mainSkill' are incompatible.
{ name: "May", age: 22, major: "cs", mainSkill: "Force"},
// [β WRONG]: 'loveToCode' does not exist in type 'MathStudents'.
{ name: "Wong", age: 20, major: "math", mainSkill: "stats", loveToCode: true},
] In simply way, you can write like this:
type StorageConfig =
| { type: 's3'; bucket: string; region: string }
| { type: 'local'; directory: string; createIfMissing: boolean };
function initStorage(config: StorageConfig) {
if (config.type === 's3') {
console.log(config.bucket); // β
OK
console.log(config.createIfMissing); // β WRONG, createIfMissing only exist when type is local
}
}Last updated on