####Typescriptはnode_modulesを見てるか?
結論:見てるとき、見てないときがあります。
"moduleResolution":
'node' (Node.js) か 'classic'の値を取ることができます。
import axios from 'axios';
"moduleResolution": "node"にしておくと、↑のように、
相対パスではない書き方でインポートしたときに、node_modulesを見に行きます。
"moduleResolution": "classic"にしておくと、カレントディレクトリにaxiosないかなー、
と見に行くだけになります。
####Webpackはnode_modulesを見てるか?
見てます。
node_modulesの中にあるaxiosの中の、d.tsファイルを見にいきます。
#.d.ts
d = declarations = 宣言
この拡張子のファイルを、型定義ファイルと言ったりします。
型の情報のみがザーッと入っています。
↓としておくと、勝手にdeclarationsファイルが作られます。
"declaration": true
型定義ファイル(.d.tsファイルが存在しない場合も高確率であります。)
#DefinitelyTyped
TypeScript 用の型定義リポジトリです。
昨今、特にフロントエンドでは TypeScript を使うのが当たり前となったが、
まだまだ過去の遺産、型定義すらない JavaScript ライブラリも多いのです。
型定義がなければ自前で書く必要があります。
「型定義を書く」とは、基本的に公式ドキュメントを TypeScript に変換することです。
#####@typesパッケージをインストールして、既存の型定義ファイルを使う方法
↓のようにimportしようとしたが、
node_modules/lodash/にd.tsファイル(Typescriptファイル)がなかった場合、
import _ from 'lodash';
まず模索すべきは、「誰かがこの型定義ファイルをすでに作っていないか?」です。
Typescriptは、node_modules/lodash/の次に、node_modules/@typesを見にいきます。
なので、仮にlodashの型定義ファイルが存在すれば、
インストールしてnode_modules/@types/に入れてあげれば良いのです。
googleで@types/lodashのような結果があれば、大体あります。
↓のようなコマンドで入れてあげます。
% npm install --save-dev @types/lodash
TypescriptでJavascriptライブラリーを使いたいときは、
まず、それのTypescript型定義ファイルが、
パッケージ(node_modules/それの名前/d.ts)にあるかどうかを確認して、
なかったらnode_modules/@typesに入れるものをgoogleで探す。
#型定義ファイルを作る方法
それでもなかったら、直接型定義ファイルを書くしかありません。
import _ from 'lodash';
↓declare module 'lodash' { }で、lodashの型を指定することができます。
declare module 'lodash' {
export function shuffle<T>(arr: T[]): T[]
}
↑これでlodashは、importされたら、shuffleというメソッドがあって、
(arr: T[ ]): T[ ]という型だよ。とTypescriptに伝えることができます。
#CDNで型定義ファイルを読み込む
これまでは、npm経由で型定義ファイルを読み込んでいました。
次に、CDN経由で、scriptから読み込む方法を見ていきます。
↓Lodash公式ページからCDN copiesをクリックして、先頭のHTMLをコピーして貼り付けます。
<link rel="stylesheet" href="style.css">
//↓これ
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.21/lodash.min.js"></script>
<script src="dist/bundle.js" defer></script>
↓その後、型を指定してあげるとエラーが消えます。
declare module 'lodash' {
export function shuffle<T>(arr: T[]): T[]
}
interface Lodash {
shuffle<T>(arr: T[]): T[]
}
declare const _: Lodash
#namespace
名前空間です。名前の衝突を防ぐ役割があります。
しかし、import, exportを優先するように言われており、あまり使う機会はありません。
↓{ }内のnameを外で使えます。
namespace myApp {
const hello = 'hello in namespace';
export const name = 'Quill';
}
const hello = myApp.name
↓namespaceで型を定義する方法
namespace myApp {
const hello = 'hello in namespace';
export const name = 'Quill';
export interface Nameable {
name: string;
}
}
let nameable: myApp.Nameable;
〜.〜のような型があれば、基本的にはnamespaceが使われていると思ってください。
#declear
「どこかでその変数が使われてるよ」という意味です。
↓constと書いてありますが、実際にメモリを用意して変数を作ってるわけではなく、
↓どこかで使われているよ。というのをお知らせしてるだけです。
declare const axios: AxiosStatic;
export default axios;
ambient declaration(アンビエント宣言)と呼ばれたりします。
ambient = 周囲、環境
#lodashの型定義ファイルの中身を見てみる
↓「トリプルスラッシュディレクティブ」
↓ ts → jsに変換したときに無くなります。
/// <reference path="./common/common.d.ts" />
↓node.js用のexport文。
export = _;
↓importを使わずに、直接読み込みなどをしたときに、_を使えるようにするための決まり文句。
export as namespace _;
####declare global { }
declare global { }の中は、
全部自動的にアンビエント宣言になり、かつグローバルで使えるようになります。
#同じ名前の値・型・namespace
Typescriptの概念では、主にデータの種類が3種類あります。
それが「値・型・namespace」です。
↓さらに、それら3つは共存することもできます。
let name: string;
interface name {}
namespace name{}
値同士・型同士はダメです。
#####例外
↓interface同士は共存できます。
interface name {
first: string
}
interface name {
second: number
}
↓classとinterfaceも共存できます。
class name {}
interface name {
first: string
}
interface name {
second: number
}
classは、interfaceも定義していると考えられます。
classが定義する型が、interfaceのような扱いを受けるからです。
↓namespace同士も共存できます。
namespace name{
const first: string = 'Peter';
}
namespace name{
const first: string = 'Peter';
}
mergeされて1つになるイメージです。
同名のプロパティは、型が違うとエラーになります。
同名のメソッドはオーバーロードされます。
・値を含んだnamespaceと変数はダメです。