ホームページ > ウェブフロントエンド > jsチュートリアル > ユニークなシンボル: タイプセーフティのためのシンボルの使用方法

ユニークなシンボル: タイプセーフティのためのシンボルの使用方法

Mary-Kate Olsen
リリース: 2025-01-16 10:48:09
オリジナル
469 人が閲覧しました

Unique Symbols: How to Use Symbols for Type Safety

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',
);
ログイン後にコピー

2 つの型をジェネリック パラメーターとして渡す方法に注目してください。 1 つ目は必須のクエリ パラメーターです (この場合は id)。 2 番目は、クエリの戻り値の型 (名前と電子メール) を表します。

内部では、query() はこれら 2 つの型を返されたオブジェクトに埋め込み、queryParamsSymbol と queryReturnSymbol に隠します。これらのシンボルは一意のシンボルとして宣言されます。つまり、それらは型空間にのみ存在し、トランスパイルされた JavaScript には表示されません。

これらのシンボルを使用してパラメータと戻り値の型を一時的に保存し、必要なときにいつでも取得できます。

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 はそれらを自動的に推測します。これは結果の上にマウスを置くことで簡単に確認でき、TypeScript はパラメータ オブジェクトのプロパティとして ID も提案します。

TypeScript プレイグラウンド

完全なコード例は、この TypeScript Playground にあります。

以上がユニークなシンボル: タイプセーフティのためのシンボルの使用方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ソース:dev.to
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
著者別の最新記事
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート