typescript学習メモ2

モジュール

パッケージ

ソフトウェアの最小単位の塊。package.jsonのdependeciesに記載されているやつ

モジュール

一般的にTypescript/Javascriptの1つのソースファイルを指す(.ts/.js)。パッケージ⊃モジュール。 バンドラー(webpackなど)を使用すると、import/exportを解析して単一のjsファイルを生成する場合がある。

export/import

export キーワードをつけると他のファイルから利用ができるようになる。 defaultキーワードをつけると、import時に自動で読み込まれる要素を選択することができる。

export const favorite = "小籠包";
export default name = "hoge"
export function fortune() {
const i = Math.floor(Math.random() * 2);
return ["小吉", "大凶"][i];
}
export class SmallAnimal {
}

import キーワードで取り込みたい要素を選択する。

// 名前を指定してimport
import { favorite, fortune, SmallAnimal } from "./smallanimal";
// リネーム
import { favorite as favoriteFood } from "./smallanimal";

//defaultを指定している場合、hogeがdefault要素になる。
import hoge from "./smallanimal";

importパス

  • 絶対パス
    • "./hoge"のピリオドから始まる形式。import文が書かれたファイルのフォルダを起点にしてファイルを探す。
  • 相対パス
    • ピリオド以外から始まる。typescriptの場合、以下の2つのパスを起点とする。
    • tsconfig.jsoncompilerOptions.baseDir起点
    • node_modulesディレクトリ以下。仮にnode_modulesが2つある場合は対象フォルダの親ディレクトリに近いパスが起点になる。(親を辿って行って最初に見つかったパスを起点にする。)

動的import

import/exportはコード実行時に全て解決している前提で処理される。しかし、起動を早くしたい場合動的にimportを行うことができる。 Promiseを返すimport()関数を利用する。(ES2018以降有効) 必要なタイミングで、const module = await import('./utils/create-zip-file');みたいに書けばよい。

まとめてexport

エントリーポイントとなるスクリプトに公開要素を1つのファイルにまとめることができる。 partA-C 3つのファイルに分けて、1つのファイルでまとめて公開する。

export {ele1, ele2} from "./partA";
export {ele3 as mainEle} from "./partB";
export {ele4 as default} from "./partC";

自動でimport

tsconfig.jsoncompilerOptions.typesで自動importするモジュールを指定できる。なんかよくわからないモジュールがあったら、ここから呼ばれているかも。

tsconfigのmodule

CommonJSとの違いの章でそういやCommonJSってなんだという感じになって調べてみた。 下記が分かりやすかった。 https://zenn.dev/naoki_mochizuki/articles/46928ccb420ee733f78f

javascriptには仕様が乱立してて、typescriptのコンパイル後にどの仕様にあわせて変換するかをtsconfig.jsのmoduleで選択できる。仕様の違いの一つにimport/exportの方法がある。 CommonJSの方法でもモジュールの読み込みなどを書くことはできるっぽいが、特に利点はないので気にしない。

console.log

console.log({object})でオブジェクトのキーと値が出力される。

console.tableでテーブル形式で表示される。 console.dirというツリー構造で表示する出力もあるが、Node.jsではサポートされていない。(console.logと同じ扱い。ブラウザの開発者ツールだとツリー形式で表示される。)

const ob = {
 test: "hoge",
 hoge: "muge"
}

console.table({ob});

┌─────────┬────────┬────────┐
│ (index) │  test  │  hoge  │
├─────────┼────────┼────────┤
│   ob    │ 'hoge''muge' │
└─────────┴────────┴────────┘

ジェネリクス

基本Javaと同じ

パラメータ制約もextendsでつけれる。型推論が効く。

function multiply<T>(value: T, n:number): Array<T> {
    const result: Array<T> = [];
    result.length = n;
    result.fill(value);
    return result;
}

//引数で型が分かるので、省略可
const value = multiply(-1, 10);
const hoge  = multiply<string>("number", 10);

console.table(value);
console.table(hoge);

extends

type Person = {
    getBirthDay(): Date;
}

function isTodayBirthday<T extends Person>(person: T): boolean {
    const today = new Date();
    // person の型は少なくともPerson を満たす型なのでgetBirthDay() メソッドが利用可能
    const birthDay = person.getBirthDay();
    return today.getMonth() === birthDay.getMonth() && today.getDate() === birthDay.
    getDate();
}

const p:Person = {
    getBirthDay: ()=> {
        return new Date("2020-01-01");
    }
}
const r = isTodayBirthday(p);
console.log(r);

下記のような型パラメータもおk。Tが決まれば、Kも決まる。T/Kが決まればUが決まるので全部解決可能。

  • T
    • オブジェクトの型
  • K
    • Tオブジェクトのプロパティ名の合併型
      • keyof T -> "Tプロパティ1" | "Tプロパティ2" | "Tプロパティ3"
  • U
    • オブジェクトのプロパティの型
function setValue<T, K extends keyof T, U extends T[K]>(obj: T, key: K, value: U) {
    obj[key] = value;
}

type ParkForm = {
    name:string,
    hasTako:boolean
}

const park: ParkForm = {
    name: "恵比寿東",
    hasTako: true
};

console.table({park});
setValue(park, "name", "神明児童遊園");
console.table({park});

オブジェクトに対するユーティリティ型がいくつか用意されている。オブジェクトのプロパティを必須にしたり、省略可能にしたりできる。下記一例。

type User = {
    name: string,
    organization:string;
}

const u:User = {
    name: "u",
    organization: "unknown"
}

//プロパティが省略可能に
const uPratial: Partial<User> = {
    name: "u"
}

type Client = {
    name?: string,
    organization?:string;
}

const c:Client = {}

//プロパティが必須に
const uRequired: Required<Client> = {
    name: "hoge",
    organization: "fuga"
}

//undefinedが抜ける
type year = NonNullable<string | number | undefined>
//重複した方が抜ける
type typeString   = Exclude<string | number | boolean, number| boolean>
//重複した型が選択される
type typeNumber   = Extract<string | number, number| boolean>

any/unkown

any/unkownを使用すると型情報がリセットされる。可能ならジェネリクスを使った方が良い。

一通り読み終わった。あまり目新しい機能はなかったけど、ジェネリクスで型を操作したり、プロパティの属性を操作したりするユーティリティは勉強になった。あまり使いどころが分からないが...