MochiuWiki : SUSE, EC, PCB
案内
メインページ
最近の更新
おまかせ表示
MediaWiki についてのヘルプ
ツール
リンク元
関連ページの更新状況
特別ページ
ページ情報
We ask for
Donations
検索
個人用ツール
ログイン
Toggle dark mode
名前空間
ページ
議論
表示
閲覧
ソースを閲覧
履歴を表示
TypeScriptの基礎 - モジュールと型のインポートのソースを表示
提供: MochiuWiki : SUSE, EC, PCB
←
TypeScriptの基礎 - モジュールと型のインポート
あなたには「このページの編集」を行う権限がありません。理由は以下の通りです:
この操作は、次のグループのいずれかに属する利用者のみが実行できます:
管理者
、new-group。
このページのソースの閲覧やコピーができます。
== 概要 == TypeScriptにおけるモジュールと型のインポートは、型安全なコードを記述する上で重要な仕組みである。<br> <br> TypeScript 3.8で導入された <code>import type</code> 構文を使用することにより、型情報のみをインポートでき、JavaScriptランタイムには一切影響を与えない。<br> これにより、バンドルサイズの削減やサイドエフェクトの回避が可能となる。<br> <br> 型定義ファイル (.d.ts) は、型情報を宣言するためのアンビエント宣言専用ファイルであり、ライブラリの型情報を別ファイルとして提供する時に使用される。<br> <code>declare</code> キーワードと組み合わせることにより、外部JavaScriptライブラリや環境固有のグローバル変数に対して型情報を付与できる。<br> <br> <u>サードパーティライブラリの型定義は、DefinitelyTypedが管理する <code>@types</code> パッケージとして提供されており、npm経由でインストールできる。</u><br> <u>型定義が存在しないライブラリに対しては、<code>declare module</code> によるシム定義や独自の型定義ファイルの作成により対処できる。</u><br> <br> TypeScript 5.0では <code>verbatimModuleSyntax</code> オプションが導入され、型インポートの明示が必須となった。<br> TypeScript 6.0ベータでは <code>strict: true</code> や <code>module: "esnext"</code> がデフォルトとなり、<code>types: []</code> がデフォルトに変更されたため、<br> 必要なパッケージの明示的な指定が求められる。<br> <br> なお、TypeScript 7.0 (Project Corsa) ではGo言語による書き直しにより10倍のコンパイル速度向上が予定されているが、言語仕様への変更はない。<br> <br> 下表に、モジュールと型インポートに関する主要な概念を示す。<br> <br> <center> {| class="wikitable" |+ モジュールと型インポートの主要概念 ! 概念 !! 概要 |- | <code>import type</code> || 型情報のみをインポートするTypeScript 3.8以降の構文<br>JavaScriptランタイムには影響を与えない。 |- | インライン型インポート || <code>import { type Foo, bar }</code> のように型と値を1つのimport文に混在させる構文<br>TypeScript 4.5以降で使用可能 |- | .d.tsファイル || 型宣言専用ファイル<br>JavaScriptコードは含まず、型情報のみを記述する。 |- | <code>declare</code> キーワード || アンビエント宣言を行うキーワード<br>JSコードを生成せず、型情報としてのみ機能する。 |- | <code>declare module</code> || 既存モジュールの型定義を宣言または拡張するための構文 |- | <code>declare global</code> || グローバル名前空間に型を追加するための構文 |- | @typesパッケージ || DefinitelyTypedが管理するコミュニティ製型定義パッケージ<br>npmで提供される。 |- | verbatimModuleSyntax || TypeScript 5.0で導入<br>import / export文をそのまま出力し、型インポートの明示を強制するオプション |} </center> <br><br> == import typeによる型のインポート == <code>import type</code> 構文は、型情報のみをインポートするための専用構文である。<br> 通常の <code>import</code> と異なり、コンパイル後のJavaScriptには何も出力されないため、ランタイムへの影響がない。<br> <br> ==== 基本的な構文 ==== <code>import type</code> の基本構文を以下に示す。<br> <br> <syntaxhighlight lang="typescript"> // 名前付き型のインポート import type { Foo, Bar } from "./module"; // デフォルト型のインポート import type DefaultType from "./module"; // 名前空間型のインポート import type * as Types from "./module"; </syntaxhighlight> <br> 型と値を同じモジュールからインポートする場合は、<code>import type</code> と通常の <code>import</code> を別々に記述する。<br> <br> <syntaxhighlight lang="typescript"> import type { User, Role } from "./types"; import { fetchUser, createUser } from "./api"; function getUser(id: string): Promise<User> { return fetchUser(id); } </syntaxhighlight> <br> <code>export type</code> を使用して、型のみをエクスポートすることもできる。<br> <br> <syntaxhighlight lang="typescript"> // 型のみのエクスポート export type { MyType, AnotherType }; // 型エイリアスの定義とエクスポート export type Point = { x: number; y: number }; </syntaxhighlight> <br> ==== import typeの利点 ==== <code>import type</code> を使用することで得られるメリットを以下に示す。<br> <br> <center> {| class="wikitable" |+ import typeを使用するメリット ! メリット !! 説明 |- | Tree-shakingの効率化 || バンドラーが不要な型を除去しやすくなり、最終的なバンドルサイズが削減される。<br>型情報はランタイムには存在しないため、バンドル対象から確実に除外される。 |- | サイドエフェクトの防止 || 通常の <code>import</code> はモジュールの初期化コードを実行する場合があるが、<br><code>import type</code> はモジュールの実行を伴わない。<br>意図しないモジュール初期化を防止できる。 |- | 循環依存の解決 || 型情報のみのインポートはランタイムには関係しないため、<br>循環参照が発生してもJavaScriptの実行に影響を与えない。 |- | コード意図の明確化 || <code>import type</code> と記述することで、<br>そのインポートが型情報のみであることが一目で分かる。 |} </center> <br> 下表に、<code>import</code> と <code>import type</code> の違いを示す。<br> <br> <center> {| class="wikitable" |+ import と import typeの違い ! 項目 !! import !! import type |- | JavaScriptへの出力 || コンパイル後も残る || コンパイル後に完全削除される。 |- | モジュールの実行 || モジュールの初期化コードが実行される || モジュールの実行を伴わない。 |- | 使用可能な対象 || 型・値・クラス・関数など全て || 型とインターフェースのみ |- | Tree-shaking || バンドラーの判断に依存する || 確実に除外される。 |- | 循環依存への影響 || ランタイムに影響を与える可能性がある || ランタイムに影響を与えない。 |- | verbatimModuleSyntax有効時 || 値のインポートに使用する || 型のインポートに必須 |} </center> <br> ==== インライン型インポート ==== TypeScript 4.5以降では、単一の <code>import</code> 文の中で型と値を混在させるインライン型インポートが利用できる。<br> <code>type</code> キーワードを各識別子の前に付けることで、その識別子が型としてのみ使用されることを示す。<br> <br> <syntaxhighlight lang="typescript"> // TypeScript 4.5以降 : インライン型インポート import { type Foo, bar, type Baz } from "./module"; // 実際の使用例 import { type User, type Role, fetchUser, createRole } from "./api"; function assignRole(user: User, role: Role): void { // fetchUser と createRole は値として使用可能 // User と Role は型としてのみ使用可能 } </syntaxhighlight> <br> <code>verbatimModuleSyntax</code> オプションが有効な場合、型としてのみ使用されるインポートには <code>type</code> キーワードの付与が必須となる。<br> <br> <syntaxhighlight lang="typescript"> // tsconfig.json で verbatimModuleSyntax: true の場合 // 型インポートには必ずtypeキーワードを付与する import { type ApiResponse, fetchData } from "./api"; </syntaxhighlight> <br><br> == 型定義ファイル (.d.ts) == 型定義ファイル (.d.ts) は、型情報のみを記述するアンビエント宣言専用のファイルである。<br> JavaScriptコードは含まず、TypeScriptコンパイラが型チェックに使用するための型情報を提供する。<br> <br> ==== .d.tsファイルとは ==== .d.tsファイルは、以下の目的で使用される。<br> <br> * JavaScriptライブラリに型情報を付与する。 *: JavaScriptで記述されたライブラリに対して、TypeScriptが型チェックを行えるよう型情報を別ファイルとして提供する。 * コンパイル済みコードに型情報を付与する。 *: TypeScriptのソースコードをコンパイルした時に自動生成され、ライブラリ利用者がIDEの補完機能を活用できるようにする。 * アンビエント宣言の定義 *: グローバル変数や環境固有のAPIに対して型情報を宣言する。 <br> <u>.d.tsファイルには実装コードを含めることができないため、関数の本体やクラスの実装を記述することはできない。</u><br> <u>全ての宣言は <code>declare</code> キーワードを使用したアンビエント宣言として記述する。</u><br> <br> ==== .d.tsファイルの基本構文 ==== .d.tsファイルに記述できる代表的な宣言の例を以下に示す。<br> <br> <syntaxhighlight lang="typescript"> // 変数の宣言 declare const VERSION: string; declare let currentUser: string | null; // 関数の宣言 declare function greet(name: string): string; declare function fetchData(url: string): Promise<unknown>; // インターフェースの宣言 declare interface Config { host: string; port: number; debug?: boolean; } // 型エイリアスの宣言 declare type ID = string | number; // クラスの宣言 declare class EventEmitter { on(event: string, listener: (...args: any[]) => void): this; emit(event: string, ...args: any[]): boolean; } // 名前空間の宣言 declare namespace MyLib { function create(options: Config): EventEmitter; const version: string; } </syntaxhighlight> <br> ==== 自動生成と手動作成 ==== .d.tsファイルはTypeScriptコンパイラによる自動生成 または 手動による作成のいずれかで用意する。<br> <br> 自動生成を行う場合は、<u>tsconfig.jsonファイル</u> に以下の設定を追加する。<br> <br> <syntaxhighlight lang="json"> { "compilerOptions": { "declaration": true, "outDir": "./dist", "declarationDir": "./dist/types", "declarationMap": true, "emitDeclarationOnly": false } } </syntaxhighlight> <br> 各オプションの説明を以下に示す。<br> <br> <center> {| class="wikitable" |+ 型宣言ファイル生成オプションの一覧 ! オプション !! 説明 |- | <code>declaration: true</code> || .d.tsファイルを自動生成する。 |- | <code>declarationDir</code> || 生成した.d.tsファイルの出力先ディレクトリを指定する。 |- | <code>declarationMap: true</code> || .d.tsファイルとソースファイルを対応付けるソースマップを生成する。<br>IDEでの定義ジャンプに使用される。 |- | <code>emitDeclarationOnly: true</code> || .d.tsファイルのみを出力し、JavaScriptファイルは出力しない。 |} </center> <br> <u>手動で.d.tsファイルを作成する場合は、ファイル名の末尾を <code>.d.ts</code> とし、<code>declare</code> キーワードを使用したアンビエント宣言のみを記述する。</u><br> <br><br> == declareキーワード == <code>declare</code> キーワードは、TypeScriptにおけるアンビエント宣言を記述するためのキーワードである。<br> アンビエント宣言は型情報としてのみ機能し、JavaScriptコードを生成しない。<br> <br> ==== アンビエント宣言の基本 ==== <code>declare</code> キーワードを使用することにより、外部で定義された変数・関数・クラスの型情報を宣言できる。<br> <br> <syntaxhighlight lang="typescript"> // 外部スクリプトで定義されたグローバル変数 declare const API_KEY: string; declare let globalState: { [key: string]: any }; // 外部ライブラリの関数 declare function setTimeout(callback: () => void, ms?: number): number; declare function clearTimeout(id: number): void; // 外部ライブラリのクラス declare class Date { constructor(); constructor(value: string | number); getTime(): number; toISOString(): string; static now(): number; } </syntaxhighlight> <br> <code>declare</code> で宣言された変数や関数は、実際の実装がJavaScript側に存在することを前提としている。<br> 宣言のみを記述し、値の割り当てや実装は含めない。<br> <br> ==== declare module ==== <code>declare module</code> は、モジュールの型定義を宣言または既存モジュールの型定義を拡張するための構文である。<br> <br> モジュールの型定義を新規に宣言する例を以下に示す。<br> <br> <syntaxhighlight lang="typescript"> // 既存のJavaScriptライブラリに型を付与する declare module "legacy-library" { export interface Config { debug: boolean; timeout: number; } export function initialize(config: Config): void; export function destroy(): void; } </syntaxhighlight> <br> 既存モジュールの型定義を拡張する例を以下に示す。<br> この手法をモジュール拡張 (Module Augmentation) と呼ぶ。<br> <br> <syntaxhighlight lang="typescript"> // expressモジュールのRequestインターフェースを拡張する declare module "express" { interface Request { userId?: string; user?: { id: string; email: string }; } } </syntaxhighlight> <br> ワイルドカードを使用して、特定の拡張子を持つファイルをモジュールとして扱う型定義も記述できる。<br> <br> <syntaxhighlight lang="typescript"> // JSONファイルをモジュールとしてインポート可能にする declare module "*.json" { const value: any; export default value; } // SVGファイルをReactコンポーネントとしてインポート可能にする declare module "*.svg" { const content: React.FC<React.SVGProps<SVGSVGElement>>; export default content; } // CSSファイルをモジュールとしてインポート可能にする declare module "*.css" { const styles: { [className: string]: string }; export default styles; } </syntaxhighlight> <br> ==== declare global ==== <code>declare global</code> は、グローバル名前空間に型を追加するための構文である。<br> モジュールファイル (import / exportを含むファイル) の中でグローバルな型を拡張する場合に使用する。<br> <br> <syntaxhighlight lang="typescript"> declare global { // WebブラウザのWindowオブジェクトを拡張する interface Window { dataLayer: any[]; gtag: (...args: any[]) => void; } // Node.jsの環境変数に型を付与する namespace NodeJS { interface ProcessEnv { NODE_ENV: "development" | "production" | "test"; DATABASE_URL: string; API_BASE_URL: string; } } // グローバル変数の宣言 (varのみ有効、let/constはモジュールローカルになる) var __DEV__: boolean; } // モジュールとして認識させるためにexportが必要 export {}; </syntaxhighlight> <br> <u>※注意</u><br> <u><code>declare global</code> ブロック内で「グローバル変数」を宣言する場合は、<code>var</code> を使用しなければならない。</u><br> <u><code>let</code> や <code>const</code> はモジュールローカルとなり、グローバルスコープには追加されない。</u><br> <br><br> == サードパーティライブラリの型定義 (@types) == TypeScriptでサードパーティのJavaScriptライブラリを使用する時、多くのライブラリは型定義ファイルを提供していない。<br> このような場合に対応するために、DefinitelyTypedプロジェクトが管理する <code>@types</code> パッケージが利用できる。<br> <br> ==== DefinitelyTypedと@typesパッケージ ==== DefinitelyTypedは、JavaScriptライブラリの型定義をコミュニティが管理する大規模リポジトリである。<br> 収録されている型定義は <code>@types/</code> プレフィックスを付けたnpmパッケージとして公開されており、<code>npm install</code> コマンドでインストールできる。<br> <br> 下表に、@typesパッケージの主な特徴を示す。<br> <br> <center> {| class="wikitable" |+ @typesパッケージの主な特徴 ! 特徴 !! 説明 |- | コミュニティによる管理 || 型定義はGitHubのDefinitelyTypedリポジトリで管理され、プルリクエストにより更新される。 |- | 開発依存としてのインストール || 型情報はコンパイル時にのみ必要なため、<code>--save-dev</code> フラグを付けてインストールする。 |- | バージョン管理 || ライブラリのバージョンに対応する型定義パッケージが提供される場合がある。 |} </center> <br> ==== @typesパッケージのインストールと使用 ==== 代表的な@typesパッケージのインストール方法を以下に示す。<br> <br> # Node.js APIの型定義 npm install --save-dev @types/node # Reactの型定義 npm install --save-dev @types/react @types/react-dom # Expressの型定義 npm install --save-dev @types/express # jQueryの型定義 npm install --save-dev @types/jquery <br> インストール後は、TypeScriptコンパイラが自動的に <u>node_modules/@typesディレクトリ</u> を参照するため、追加の設定なしに型情報が使用可能となる。<br> <br> <syntaxhighlight lang="typescript"> // @types/nodeをインストール後、Node.js APIに型が付与される import * as fs from "fs"; import * as path from "path"; const filePath: string = path.join(__dirname, "data.json"); const content: Buffer = fs.readFileSync(filePath); </syntaxhighlight> <br> ==== typeRootsとtypesの設定 ==== tsconfig.jsonファイルの <code>typeRoots</code> および <code>types</code> オプションを使用して、型定義の探索範囲を制御できる。<br> <br> <syntaxhighlight lang="json"> { "compilerOptions": { "typeRoots": [ "./src/types", "./node_modules/@types" ], "types": ["node", "jest", "react"] } } </syntaxhighlight> <br> 下表に、各オプションの説明を示す。<br> <br> <center> {| class="wikitable" |+ 型定義ファイル探索オプションの一覧 ! オプション !! 説明 |- | <code>typeRoots</code> || 型定義ファイルを探索するディレクトリのリストを指定する。<br>指定した場合、<code>node_modules/@types</code> は自動的に探索されなくなるため、<br>明示的に追加する必要がある。 |- | <code>types</code> || 自動的にインクルードする <code>@types</code> パッケージ名のリストを指定する。<br>TypeScript 6.0以降ではデフォルト値が空配列(<code>[]</code>)に変更されたため、<br>使用するパッケージを明示的に指定する必要がある。 |} </center> <br><br> == 型定義が存在しない場合の対処 == <code>@types</code> パッケージが存在しないライブラリや型定義が不完全なライブラリを使用する場合、いくつかの対処方法がある。<br> <br> 下表に、型定義が存在しない場合の対処法の比較を示す。<br> <br> <center> {| class="wikitable" |+ 型定義が存在しない場合の対処法の比較 ! 対処法 !! 型安全性 !! 実装コスト !! 推奨される場面 |- | declare moduleによるシム定義 || 中程度 || 低〜中 || 利用するAPIが限定的な場合 |- | 独自の型定義ファイルの作成 || 高い || 高い || 長期利用・チーム開発での使用 |- | any型へのフォールバック || 低い || 最低限 || 一時的な対処・プロトタイプ開発 |- | skipLibCheck: true || 影響なし || 設定のみ || 型定義ファイルのエラーを無視したい場合 |} </center> <br> ==== declare moduleによるシム定義 ==== <code>declare module</code> を使用して、型定義が存在しないライブラリの型をシムとして定義できる。<br> プロジェクト内に型定義ファイルを作成し、必要なAPIの型情報を記述する。<br> <br> <syntaxhighlight lang="typescript"> // src/types/shims.d.tsファイル declare module "legacy-library" { export interface Config { debug: boolean; timeout: number; retryCount?: number; } export function initialize(config: Config): void; export function destroy(): void; export function getVersion(): string; } declare module "another-untyped-lib" { export default function process(input: string): string; } </syntaxhighlight> <br> 作成した型定義ファイルをTypeScriptが認識するよう、tsconfig.jsonファイルの <code>include</code> または <code>typeRoots</code> に追加する。<br> <br> ==== 独自の型定義ファイルの作成 ==== ライブラリを長期的に使用する場合やチーム開発で型安全性を維持したい場合は、詳細な型定義ファイルを作成することが推奨される。<br> <br> <syntaxhighlight lang="typescript"> // src/@types/my-custom-lib/index.d.tsファイル export interface InitOptions { apiKey: string; endpoint: string; timeout?: number; } export interface Data { id: string; payload: Record<string, unknown>; timestamp: number; } export interface MyCustomLib { initialize(options: InitOptions): void; getData(): Promise<Data>; postData(data: Partial<Data>): Promise<{ success: boolean }>; destroy(): void; } declare const myCustomLib: MyCustomLib; export default myCustomLib; </syntaxhighlight> <br> 独自の型定義ファイルを <code>src/@types</code> ディレクトリに配置する場合、tsconfig.jsonファイルに以下の設定を追加する。<br> <br> <syntaxhighlight lang="json"> { "compilerOptions": { "typeRoots": [ "./src/@types", "./node_modules/@types" ] } } </syntaxhighlight> <br> ==== any型へのフォールバック ==== 型定義の作成が困難な場合や一時的な対処として、<code>any</code> 型を使用したシム定義を行うことができる。<br> 型安全性は失われるが、コンパイルエラーを解消して開発を継続することができる。<br> <br> <syntaxhighlight lang="typescript"> // src/types/fallback.d.tsファイル // モジュール全体をany型として宣言する declare module "untyped-library" { const content: any; export = content; } // 特定の関数のみをany型として宣言する declare module "partially-typed-lib" { export function knownFunction(input: string): string; export const unknownFeature: any; } </syntaxhighlight> <br> 型定義ファイル自体のエラーを無視したい場合は、tsconfig.jsonファイルに <code>skipLibCheck: true</code> を設定する。<br> <u>しかし、<code>skipLibCheck</code> は型定義ファイルの型チェックを完全にスキップするため、使用は必要最低限にとどめることが推奨される。</u><br> <br> <syntaxhighlight lang="json"> { "compilerOptions": { "skipLibCheck": true } } </syntaxhighlight> <br><br> == 関連情報 == * [[TypeScriptの基礎 - 列挙型と定数]] * [[TypeScriptの基礎 - 型の互換性と構造的部分型]] <br><br> {{#seo: |title={{PAGENAME}} : Exploring Electronics and SUSE Linux | MochiuWiki |keywords=MochiuWiki,Mochiu,Wiki,Mochiu Wiki,Electric Circuit,Electric,pcb,Mathematics,AVR,TI,STMicro,AVR,ATmega,MSP430,STM,Arduino,Xilinx,FPGA,Verilog,HDL,PinePhone,Pine Phone,Raspberry,Raspberry Pi,C,C++,C#,Qt,Qml,MFC,Shell,Bash,Zsh,Fish,SUSE,SLE,Suse Enterprise,Suse Linux,openSUSE,open SUSE,Leap,Linux,uCLnux,電気回路,電子回路,基板,プリント基板 |description={{PAGENAME}} - 電子回路とSUSE Linuxに関する情報 | This page is {{PAGENAME}} in our wiki about electronic circuits and SUSE Linux |image=/resources/assets/MochiuLogo_Single_Blue.png }} __FORCETOC__ [[カテゴリ:Rust]][[カテゴリ:Web]]
TypeScriptの基礎 - モジュールと型のインポート
に戻る。
案内
メインページ
最近の更新
おまかせ表示
MediaWiki についてのヘルプ
ツール
リンク元
関連ページの更新状況
特別ページ
ページ情報
We ask for
Donations
Collapse