نمادهای منحصر به فرد: نحوه استفاده از نمادها برای ایمنی نوع

اگر مدتی را صرف کار با React کرده اید، ممکن است به طور تصادفی با React Query برخورد کرده باشید queryOptions()
تابع اجرای آن به طرز تکان دهنده ای ساده به نظر می رسد:
export function queryOptions(options: unknown) {
return options
}
با این حال، جادوی واقعی در امضاهای عملکرد بیش از حد آن نهفته است. بنابراین، چه چیز خاصی در مورد آن وجود دارد؟
اگر مطمئن نیستید که عملکرد بیش از حد بارگذاری شده چیست، می توانید این پست را بررسی کنید: بارگذاری بیش از حد تابع: چگونه با امضاهای چند عملکردی برخورد کنیم
پرس و جوهای پایگاه داده تایپ شده
با الهام از رویکرد React Query، من یک تابع کمکی را گردآوری کردم که ممکن است برای افرادی که خارج از React کار می کنند مفید باشد: راهی ساده برای ایجاد پرس و جوهای تایپ شده، به عنوان مثال، پرس و جوهای SQL.
export declare const queryParamsSymbol: unique symbol;
export declare const queryReturnSymbol: unique symbol;
export type Query<
TParams extends Record<string, any> = Record<string, any>,
TReturn extends Record<string, any> | undefined = undefined,
TStatement extends string = string,
> = {
statement: TStatement;
[queryParamsSymbol]: TParams;
[queryReturnSymbol]: TReturn;
};
export function query<
TParams extends Record<string, any> = Record<string, any>,
TReturn extends Record<string, any> | undefined = undefined,
TStatement extends string = string,
>(statement: TStatement): Query<TParams, TReturn> {
return { statement: statement } as Query<TParams, TReturn, TStatement>;
}
شبیه به queryOptions()
، این تابع به خودی خود بسیار کسل کننده است: یک دستور SQL را می گیرد، آن را در یک شی از نوع می پیچد Query
، و آن را برمی گرداند.
در اینجا یک مثال سریع از نحوه نامگذاری آن آورده شده است:
const getUserById = query<{ id: number }, { name: string; email: string }>(
'SELECT name, email FROM users WHERE id = $id',
);
توجه کنید که چگونه دو نوع را به عنوان پارامترهای عمومی ارسال می کنیم. اولی پارامترهای پرس و جو مورد نیاز است – در این مورد، id
. دومی نشان دهنده نوع بازگشت پرس و جو است – name
و email
.
زیر کاپوت، query()
این دو نوع را در شیء برگشتی تعبیه می کند و آنها را در آن ذخیره می کند queryParamsSymbol
و queryReturnSymbol
. این نمادها به عنوان اعلام می شوند unique symbol
، به این معنی که آنها فقط در فضای تایپ وجود دارند و در جاوا اسکریپت ترجمه شده ظاهر نمی شوند.
من از این نمادها برای ذخیره موقت پارامترها و انواع برگرداندن آنها استفاده می کنم و هر زمان که به آنها نیاز داشته باشم آنها را بازیابی می کنم.
type InferQueryParams<TQuery> = TQuery extends Query<infer Params, any> ? Params : never;
type UserQueryParams = InferQueryParams<typeof getUserById>;
// ^? { id: number }
type InferQueryReturn<TQuery> = TQuery extends Query<any, infer Return> ? Return : never;
type UserQueryReturn = InferQueryReturn<typeof getUserById>;
// ^? { name: string; email: string }
را InferQueryParams
و InferQueryReturn
فقط انواع ابزار برای تأیید اینکه پارامتر و انواع برگشتی ما به درستی استنباط شده اند. ممکن است واقعاً به آنها نیاز نداشته باشید، اما آنها برای تأیید رویکرد ما مفید هستند.
مشتری پایگاه داده
اکنون که می دانیم چگونه پارامترها را در یک شی پرس و جو جاسازی کنیم و انواع برگردانیم، چگونه این کوئری ها را اجرا کنیم؟ بیایید نگاهی به یک سرویس گیرنده پایگاه داده ساده بیندازیم که می تواند پرس و جوهای تایپ شده ما را اجرا کند:
class DatabaseClient {
async execute<
TParams extends Record<string, any>,
TReturn extends Record<string, any>
>(
query: Query<TParams, TReturn>,
params: TParams,
): Promise<Array<TReturn>> {
// execute the query and return the results
// ...
return [];
}
}
const db = new DatabaseClient();
// Return type and parameters are inferred from the query object
const result = await db.execute(getUserById, { id: 1 });
// ^? { id: number }
// ^? Array<{ name: string; email: string }>
console.log(result);
در این مثال، تایپ خود را پاس می کنیم getUserById
پرس و جو شی به db.execute()
روش از آنجا که Query
نوع شامل هر دو پارامتر و اطلاعات نوع بازگشتی است، TypeScript به طور خودکار آنها را استنباط می کند. ما به راحتی می توانیم با نگه داشتن ماوس روی آن تایید کنیم result
و TypeScript نیز پیشنهاد خواهد کرد id
به عنوان دارایی ما parameters
شی
زمین بازی TypeScript
می توانید نمونه کد کامل را در این زمین بازی TypeScript پیدا کنید.