انواع لیترال (Literal Types)
«نوع لیترال (Literal Type)» یعنی مقدار دقیق مجاز است. مثلا فقط "east". بنابراین کد دقیق تر و امن تر می شود. مثل برچسب روی دکمه آسانسور که فقط طبقات مجاز را می پذیرد.
لیترال رشته ای (String Literal)
لیترال رشته ای یعنی فقط چند رشته مشخص. بنابراین اشتباه تایپی زودتر لو می رود.
let direction: 'north' | 'south' | 'east' | 'west';
direction = 'north';
direction = 'south';
// direction = 'up';
function move(direction: 'north' | 'south' | 'east' | 'west') {
console.log(`Moving ${direction}`);
}
move('east');
لیترال عددی (Numeric Literal)
لیترال عددی یعنی فقط اعداد خاص. مثل تاس 1 تا 6.
let diceRoll: 1 | 2 | 3 | 4 | 5 | 6;
diceRoll = 1;
diceRoll = 6;
// diceRoll = 7;
function rollDice(): 1 | 2 | 3 | 4 | 5 | 6 {
return (Math.floor(Math.random() * 6) + 1) as 1 | 2 | 3 | 4 | 5 | 6;
}
const result = rollDice();
console.log(`You rolled a ${result}`);
لیترال بولی (Boolean Literal)
اینجا مقدار دقیق true یا false مهم است. بنابراین منطق شفاف تر می شود.
type YesOnly = true;
function alwaysSucceed(): true {
return true;
}
type SuccessFlag = true | 'success' | 1;
type FailureFlag = false | 'failure' | 0;
function processResult(result: SuccessFlag | FailureFlag) {
if (result === true || result === 'success' || result === 1) {
console.log('Operation succeeded');
}
else {
console.log('Operation failed');
}
}
processResult(true);
processResult('success');
processResult(1);
processResult(false);
لیترال در آبجکت ها
می توانیم شکل دقیق پاسخ را مشخص کنیم. مثل فرم با گزینه های ثابت.
type HTTPSuccess = {
status: 200 | 201 | 204;
statusText: 'OK' | 'Created' | 'No Content';
data: any;
};
type HTTPError = {
status: 400 | 401 | 403 | 404 | 500;
statusText: 'Bad Request' | 'Unauthorized' | 'Forbidden' | 'Not Found' | 'Internal Server Error';
error: string;
};
type HTTPResponse = HTTPSuccess | HTTPError;
function handleResponse(response: HTTPResponse) {
if (response.status >= 200 && response.status < 300) {
console.log(`Success: ${response.statusText}`);
console.log(response.data);
}
else {
console.log(`Error ${response.status}: ${response.statusText}`);
console.log(`Message: ${response.error}`);
}
}
const successResponse: HTTPSuccess = {
status: 200,
statusText: 'OK',
data: { username: 'john_doe', email: 'john@example.com' }
};
const errorResponse: HTTPError = {
status: 404,
statusText: 'Not Found',
error: 'User not found in database'
};
handleResponse(successResponse);
handleResponse(errorResponse);
Template Literal Types
با Template Literal Types می توان رشته های الگو دار ساخت. مثل "north-5km".
type Direction = 'north' | 'south' | 'east' | 'west';
type Distance = '1km' | '5km' | '10km';
type DirectionAndDistance = `${Direction}-${Distance}`;
let route: DirectionAndDistance;
route = 'north-5km';
route = 'west-10km';
// route = 'north-2km';
type EventType = 'click' | 'hover' | 'scroll';
type EventTarget = 'button' | 'link' | 'div';
type EventName = `on${Capitalize<EventType>}${Capitalize<EventTarget>}`;
type User = {
id: number;
name: string;
email: string;
createdAt: Date;
};
type GetterName<T> = `get${Capitalize<string & keyof T>}`;
type UserGetters = {
[K in keyof User as GetterName<User>]: () => User[K];
};
type ExtractRouteParams<T extends string> =
T extends `${string}:${infer Param}/${infer Rest}`
? Param | ExtractRouteParams<Rest>
: T extends `${string}:${infer Param}`
? Param
: never;
type Params = ExtractRouteParams<'/users/:userId/posts/:postId'>;
type CssUnit = 'px' | 'em' | 'rem' | '%' | 'vh' | 'vw';
type CssValue = `${number}${CssUnit}`;
let width: CssValue = '100px';
let height: CssValue = '50%';
// type-safe SQL builder demo
type Table = 'users' | 'products' | 'orders';
type Column<T extends Table> =
T extends 'users' ? 'id' | 'name' | 'email' | 'created_at'
: T extends 'products' ? 'id' | 'name' | 'price' | 'in_stock'
: T extends 'orders' ? 'id' | 'user_id' | 'total' | 'status'
: never;
type WhereCondition<T extends Table> = {
[P in Column<T>]?: {
equals?: any;
notEquals?: any;
in?: any[];
};
};
function query<T extends Table>(table: T, where?: WhereCondition<T>): `SELECT * FROM ${T}${string}` {
return `SELECT * FROM ${table}` as const;
}
const userQuery = query('users', {
name: { equals: 'John' },
created_at: { in: ['2023-01-01', '2023-12-31'] }
});
گام های عملی
- برای مجموعه ثابت، لیترال تعریف کن.
- با یونین، مقادیر مجاز را محدود کن.
- در آبجکت ها، وضعیت ها را دقیق کن.
- با Template Literals، الگوهای رشته ای بساز.
- در صورت نیاز، از enum هم کمک بگیر.
جمع بندی سریع
- لیترال، مقدار دقیق را محدود می کند.
- خطاها زودتر پیدا می شوند.
- در APIها بسیار مفید است.
- Template Literal Types الگو می سازد.
مطالب مرتبط: استنتاج نوع، انواع نگاشتی. همچنین برای تاکید سئو: انواع لیترال تایپ اسکریپت را مرور کن.