参考サイト:これだけはおさえておきたいTypeScriptの機能
※体系的に学べるというよりも、実際の開発で頻繁に使用するもの、これだけはおさえておきたい機能を中心に取り上げる。
1.プリミティブ型
2.リテラル型
3.anyとunknown
4.構造的部分型 (Structural Subtyping)
5.型ガード (Type Guards)
6.関数 (Functions)
7.配列(Array)
8.タプル(Tuple)
9.列列挙(Enum)
10.タイプエイリアス(Type Aliases)
11.ユニオン型(Union Types)
12.オブジェクト(Object)
13.インターフェース(Interfaces)
14.クラス(Classes)
15.型推論(Type Inference)
16.ジェネリクス(Generics)
17.ジェネリクスが使われている標準ライブラリ
18.型パラメーターの制約
19.デフォルト型パラメータ
20.Promise/async/await
21.ユーティリティ型(Utility Type)
22.定義ファイル
23.tsconfig.json Deep Drive
24.import / export / require
25.型変数(Type Variables)
1.プリミティブ型
プリミティブ型は一般的には振る舞いを持ちません。
→メソッドを持たないから
//種類
>undefined
→値がないことを示す値です。
→他言語のnullのように設定されなかったときに代入されます。
>null
→意図的に値を指定しないことを強調する際、undefinedでなくnullとします。
→ラッパークラスを持ちません。
>boolean
→trueかfailsのみ持ちます。
→ラッパークラスはBooleanです。
>number
→数値を扱います。
→ラッパークラスはNumberです。
→メソッド呼び出し時は、整数でも小数点を付けます。
>string
→ラッパークラスはSrtingです。
→「+」で連結の演算子を処理できます。
→テンプレートリテラル(テンプレートリテラル)
→バッククォートを使う
・改行出来る
・変数展開出来る
>symbol
→ラッパークラスはSymbol
→一意性のために使われます。
→外部からアクセスしてほしくないメソッドに対してsymbol型の名前を与え、その値を外部に露出させないことで疑似的なprivateプロパティ、メソッドを実現していました。
>bigint
→ラッパークラスはBigInt
→number型よりも大きな整数を扱います。
→number型と一緒に計算できません。
※ES2020 未満の場合、bigint リテラルは使用できません。
2.リテラル型
リテラル型とは、プリミティブ型の特定の値だけを許容する型です。
const impossible: false = false;
const three: 3 = 3;
const radetzky: 'Radetzky' = 'Radetzky';
constと何が違うのか?
→constはECMAScriptで定められている定数の宣言です。
→リテラル型はプリミティブ型の特定の値だけを許容する型です。
→実際に動作する時は型のないJavaScriptになります。他の値が代入できないという制限はもはやなくなっている状態なので、リテラル型をあたかも定数のように使うことは避けてください。
使い方
→ユニオン型との相性がよく併用して使われることが多いです。
ユニオン型の宣言
let mag1: 1|2|3|4|5 = 3;
let mag2: 1|2|3|4|5 = 6; // -> error: 型 '6' を型 '1 | 3 | 2 | 4 | 5' に割り当てることはできません。
→異なるデータ型, プリミティブ型, クラスのインスタンスを含むオブジェクト型でも構成できます。
class How {
public food: string;
constructor(food: string) {
this.food = food;
}
}
const how = new How('Apple');
console.log(how.food); // -> Apple
let eat1: How|string = how.food;
let eat2: How|string = 'Apple';
console.log(eat1); // -> Apple
console.log(eat2); // -> Apple
→リテラル型はそのリテラルが所属するデータ型の派生型として解釈されます。この使い方はジェネリクスで頻出します。初めはプリミティブ型の派生型とは一体何かと面食らうことがあるかもしれません。
ジェネリクス
※number型のNaN, Infinity, -Infinityはリテラル型として使うことができません。
3.anyとunknown
→型が不定のとき、TypeScriptではanyまたはunknownという型を使います。
→どんな値も代入できます。
違い
→any型に代入したオブジェクトのプロパティ,メソッドは使用できます。
→unknown型に代入したオブジェクトのプロパティ,メソッドは使用できません。
console.log(anyCar); // -> 33
console.log(unkCar); // -> 33
console.log(anyName); // -> Jukiya
console.log(unkName); // -> Jukiya
console.log(anyCar.toFixed(1)); // -> 33.0
console.log(unkCar.toFixed(1)); // -> Object is of type 'unknown'
console.log(anyName.length); // -> 6
console.log(unkName.length); // -> Object is of type 'unknown'
→any型は言い換えればTypeScriptが型のチェックを放棄した型であり、型という利点を手放しているのと同じです。
→unknown型は一貫してTypeScriptがプロパティ、メソッドへのアクセスを行わせません。意図しないランタイム時のエラーを防止します。
※tsconfig.jsonにはこのany型の使用を防ぐためのオプションとしてnoImplicitAnyがあります。
tsconfig.jsonを設定する
→関係のないクラスへ型アサーションする時にany,unknownを使います
const cat: Cat = new Cat();
const duck1: Duck = cat as any as Duck;
const duck2: Duck = cat as unknown as Duck;
4.構造的部分型 (Structural Subtyping)
基本型(supertype)
→ある元となる型
派生型(subtype)
→基本型の継承関係にある型
→違いを理解しておくことで、より安全で堅牢なTypeScriptができるようになります。
・公称型(nominal typing)
→Java, C++で採用されている定義です。
→ある型を基本型にする派生型は、互いに置換ができません。
・構造的部分型(structural subtyping)
→Go, TypeScriptで採用されている定義です。
→その型の見た目(シグネチャ)が等しければ置換可能であるという点が公称型と大きく異なっています。
→公称型ほど硬くはなく、とはいえ型の恩恵は受けたいというやや緩い型付けです。
5.型ガード (Type Guards)
JavaScriptでは変数の型が何であるかを判別できる演算子があります。
種類
・typeof
→プリミティブ型に対して使用
・instanceof
→クラスに対して使用
型ガードとは
TypeScriptはこれらの演算子で型を判別したあと、そのif,caseブロックではその変数はキャストをすることなくその型であるかのように振る舞うことができます。
Type Predicate
→自分でその変数が意図する型であるかを判定することができます。
宣言
→戻り値がboolean型の関数に対して適用できます。
function isDuck(animal: Animal): animal is Duck {
// ...
}
// これで関数isDuck()は、animalはDuck型として解釈されます。
6.関数 (Functions)
宣言の仕方
//名前付き関数(Normal Functions)
function increment(num: number): number {
return num + 1;
}
//匿名関数(Anonymous Functions)
const increment = function(num: number): number {
return num + 1;
};
//匿名かつアロー関数(Arrow Functions)
const increment = (num: number): number => {
return num + 1;
};
this
class JetLag {
private message: string;
public constructor(message: string) {
this.message = message;
}
public replyArrow(ms: number): void {
setTimeout(() => {
console.log(this.message);
}, ms);
}
}
const jetlag: JetLag = new JetLag('i can hear you later');
jetlag.replyArrow(2000);
関数の型
→匿名関数、匿名かつアロー関数では変数に代入していることからわかるように、関数も型による表現が可能です。
(num: number) => number;
→匿名かつアロー関数は、実体を除けば次の形をしています。
(num: number): number => {...};
→オブジェクト風の書き方もあります。
type Increment = {
(num: number): number;
};
引数(Arguments)
→関数の入力値である引数は、要求する型の変数を、要求する数だけ入力しなければいけません。
type Point = {
x: number;
y: number;
};
function distance(p: Point): number {
return (p.x ** 2 + p.y ** 2);
}
console.log(distance({x: 1, y: 1}));
→引数を省略したいときは、オプション引数とデフォルト引数を使用することができます。
function distance(p1: Point, p2?: Point): number {
let p0: Point | undefined = p2;
if (typeof p0 === 'undefined') {
p0 = {
x: 0,
y: 0
};
}
return ((p1.x - p0.x) ** 2 + (p1.y - p0.y) ** 2) ** (1 / 2);
}
※オプション引数の後ろに普通の引数を書くことはできません。
→デフォルト引数を使用すると、意図を明確にできます。
const p0: Point = {
x: 1,
y: 2
};
function distance(p1: Point, p2: Point = p0): number {
return ((p1.x - p2.x) ** 2 + (p1.y - p2.y) ** 2) ** (1 / 2);
}
distance(q1, q2);
distance(q1);
distance(q1, undefined);
残余引数(Rest Parameters)
可変の引数のことです。
可変の引数の前に...を付ければ、可変引数を受け付け、それらを配列として受けることができます。
分割代入(Destructuring assignment)
→複数引数を記述する時、順番を間違った時に誤用を防ぐ
bmi(170, 65);
// -> 22.49134948096886
bmi(65, 170);
// -> 402.36686390532543
//↓↓↓↓//
bmi({height: 170, weight: 65});
bmi({weight: 65, height: 170});
※デフォルト引数を併用できます。
引数のthis
関数(アロー関数以外)とクラスのメソッドの第1引数はthisという特殊な引数を受けることができます。
戻り値 (Return Value)
あえて書かなくてもTypeScript側で補完し、関数の戻り値として提供してくれますが、意図しない戻り値を返していないかの検査が働くので書いた方がよいでしょう。
戻り値がないことを明示したいときはvoidと書きます。
戻り値のthis
オーバーロード(Overload)
→関数の名称は同じでありながら異なる引数、戻り値を持つことができる機能です。
定義
→その関数が受け付けたい引数、戻り値の組を実装する関数の上に書きます。
function distance(p: Point): number;
function distance(p1: Point, p2: Point): number;
function distance(x: number, y: number): number;
function distance(x1: number, y1: numebr, x2: number, y2: number): number;
7.配列(Array)
配列の型は2パターン
// array
const array1: T[] = [];
// generic
const array2: Array<T> = [];
※違いはないが、arrayが一般的
8.タプル(Tuple)
戻り値で複数で異なる型の値を返したい時に使う
非同期通信で、時間のかかる処理を直列でなく並列で行いたいとき
配列が抱える問題
異なる型が含まれる配列の型にany or unknownで制限しないと問題となる。
使い方
const list: [number, string, boorean] = tuple();
function tuple() {
return [1, 'ok', true];
}
または、
function tuple(): [number, string, boolean] {
//...
return [1, 'ok', true];
}
タプルへのアクセス
→それぞれの型の値が持っているプロパティ, メソッドを使える
const list: [number, string, boolean] = tuple();
list[0].toExponential();
list[1].length;
list[2].valueOf();
9.列挙型(Enum)
変数に値を自動的に割り当てる型になります。
enum DayOfTheWeek {
SUN,
MON,
TUE,
WED,
THU,
FRI,
SAT
}
console.log(DayOfTheWeek.SUN); // 0
console.log(DayOfTheWeek.MON); // 1
console.log(DayOfTheWeek.TUE); // 2
function dayOff(today: DayOfTheWeek) {
if (today === DayOfTheWeek.SUN || today === DayOfTheWeek.SAT) {
console.log('Happy Day!!');
} else {
console.log('Today is work.');
}
}
dayOff(DayOfTheWeek.SUN);
// -> 'Happy Day!!'
dayOff(DayOfTheWeek.MON);
// -> 'Today is work.'
数値列挙 / 文字列列挙
メンバに値を代入することもできます。その場合は値が重複しないようにしましょう。
enum DayOfTheWeek {
SUN = 1, // 1
MON, // 2
TUE, // 3
WED, // 4
THU, // 5
FRI, // 6
SAT // 7
}
enum Direction {
Up = "UP",
Down = "DOWN",
Left = "LEFT",
Right = "RIGHT",
}
10.タイプエイリアス(Type Aliases)
オブジェクト型の変数の値を定義する時に使う
エラーの例
const person: object = {
surname: 'Fauré',
givenName: 'Gabriel'
};
console.log(person.surname); // error: プロパティ「surname」はタイプ「object」に存在しません。
タイプエイリアスを使った例
type Person = {
surname: string;
givenName: string;
};
const person: Person = {
surname: 'Fauré',
givenName: 'Gabriel'
};
ユニオン型との組み合わせで効果を発揮する
type SystemSupportLanguage = 'en' | 'fr' | 'it' | 'es';
11.ユニオン型(Union Types)
→変数に対して複数の型を定義出来る
→プログラムによっては、その変数がいろんな型になりえる場合がある。
→そんな時にユニオン型で複数の型で定義する
const numOrFalse: number | false = union();
タイプエイリアスでも使える
type PHPLikeReturnValue = number | false;
12.オブジェクト(Object)
オブジェクト (Object)
クラスという概念が追加される前のオブジェクトと言えばコレ。
const pokemon = {
name: 'pikachu',
no: 25,
genre: 'mouse pokémon',
height: 0.4,
weight: 6.0,
};
オブジェクト型の変数は、その変数のプロパティやメソッドにアクセスできません
const pikachu: object = {
name: 'pikachu',
no: 25,
genre: 'mouse pokémon',
height: 0.4,
weight: 6.0,
};
pikachu.no; // error: プロパティ「no」はタイプ「object」に存在しません。
→タイプエイリアスを使って対処します。
→オブジェクトのプロパティは上書き可能
分割代入
const {
name,
no,
genre
}: Wild = safari();
→ネストしたオブジェクトの分割代入
→分割代入しつつ名前を変更する
→配列にも分割代入出来る
→引数にも分割代入出来る
タイプエイリアス?それともインターフェース?
→タイプエイリアスとインターフェースは機能が似通っており困惑します。
13.インターフェース(Interfaces)
型を表現する方法のひとつ
定義
TypeScriptではインターフェースは型注釈として利用できる
interface Person {
name: string;
age: number;
}
const taro: Person = {
name: '太郎',
age: 12,
}
インターフェース単体では利用されず、特定のクラスがインターフェースを継承し実装を追加することで初めて効果を発揮します。
継承(extends)
定義済みのインターフェースを継承して新たにインターフェースを定義することができます。
interface Person {
name: string;
age: number;
}
interface Student extends Person {
grade: number; // 学年
}
interface Teacher extends Person {
students: Student[]; // 生徒
}
const studentA: Student = {
name: '花子',
age: 10,
grade: 3,
}
const teacher: Teacher = {
name: '太郎',
age: 30,
students: [studentA],
}
→プロパティを部分型に宣言しなおすこともできます。
実装(Implementation)
インターフェースをクラスが実装することもできます。
→複数インターフェース指定OK
※同名プロパティが違う型で衝突すると、never型になり、値の代入ができなくなります。
interface Measurements {
bust: number;
waist: number;
hip: number;
}
interface SensitiveSizes {
bust: 'secret';
waist: 'secret';
hip: 'secret';
}
class Adorescent implements Measurements, SensitiveSizes {
// bust: never;
// waist: never;
// hip: never;
}
問題
interfaceはJavaScriptに存在しないため、その型のinterfaceを判定することはできません。
→解消するには、型ガードを実装します。
type UnknownObject<T extends object> = {
[P in keyof T]: unknown;
};
function isStudent(obj: unknown): obj is Student {
if (typeof obj !== 'object') {
return false;
}
if (obj === null) {
return false;
}
const {
name,
age,
grade
} = obj as UnknownObject<Student>;
if (typeof name !== 'string') {
return false;
}
if (typeof age !== 'number') {
return false;
}
if (typeof grade !== 'number') {
return false;
}
return true;
}
14.クラス(Classes)
書式
class クラス名 {
プロパティ;
constructor(){}
メソッド(){
処理
}
}
例
class Greeter {
greeting: string;
constructor(message: string) {
this.greeting = message;
}
greet() {
return "Hello, " + this.greeting;
}
}
let morning = new Greeter('World!');
console.log(morning.greet());
継承
extendsを使います。
class Food {
foodAction() {
return 'Foodクラス内の関数です';
}
}
class Meat extends Food {
meatAction() { return 'Meatクラス内の関数です';
}
}
let parentClass = new Food();
let childClass = new Meat();
console.log(parentClass.foodAction());
console.log(childClass.meatAction());
console.log(childClass.foodAction());
→継承したサブクラス(子)は、スーパークラスのプロパティ,メソッドを使える。
abstract
抽象クラス作成時に宣言する
抽象クラスとは
直接インスタンス化(new)することができず、必ずスーパークラスとして利用することを保証するものです。
abstract class Food {
constructor(protected name: string , protected calorie: number) { }
showDebug() {
console.log(`name = ${this.name} `);
console.log(`calorie = ${this.calorie}kcal `);
}
abstract keepRefrigerated(): boolean;
}
class Meat extends Food { } // エラー:非抽象クラス 'Meat' はクラス 'Food' からの継承抽象メンバー 'keepRefrigerated' を実装しません。
アクセス修飾子
>(宣言無し) : publicになる
>public : どこからでもアクセス可能
>protected : 自身クラス, サブクラスからアクセス可能
>private : 自身クラスのみアクセス可能
→コンストラクタの引数にも設定できる
→メソッドの引数には設定できない
readonly修飾子
→読み取り専用プロパティに出来る
→宣言時かコンストラクタで初期化が必要
class Octopus {
readonly name: string;
readonly numberOfLegs: number = 8;
constructor (theName: string) {
this.name = theName;
}
}
const dad = new Octopus("Man with the 8 strong legs");
dad.name = "Man with the 3-piece suit"; // error! name is readonly.
15.型推論(Type Inference)
コンパイラが型を自動で判別してくれます。
すべての箇所で型アノテーションを書く必要がなく、コード記述量を大幅に減らすことができます
// let x: number
let x = 1;
// Error: Type 'string' is not assignable to type 'number'.
x = 'hello';
いつ使う?
明確な正解はありません。
コードの読みやすさを考慮して、すべての箇所で型を書いてもよいですし、少しでも記述量を減らすために型推論をしてくれる箇所は積極的に型を書かない選択をしてもOKです。
場面
関数の引数の型を省略した場合
型を決定するヒントがないのでany型になります。
function add(a, b) {
return a + b;
}
// 引数はany型なので、何でも渡せる
const x = add([1, 2, 3], 'hello');
クラスのインスタンスプロパティの型を省略した場合
→コンストラクタで値が代入される場合は、代入する値で型が推論されます。
→setterなどを利用して変数に値を代入する場合はany型として推論されます。
class User {
private _name;
constractor(name: string) {
this._name = name;
}
hello() {
// _name は string型 として型推論されるので、コンパイルエラー
// Property 'hoge' does not exist on type 'string'.(2339)
console.log(`Hello, ${this._name.hoge()}`);
}
private _setname;
set name(value: string) {
this._setname = value;
}
hello() {
// _name は any型として型推論されるので、コンパイルエラーにならない。
console.log(`Hello, ${this._name.hoge()}`);
}
}
16.ジェネリクス(Generics)
型の安全性とコードの共通化を両立することができます。
「型の安定性」と「コードの共通化」はシーソーの法則になりがちなのです。
function chooseRandomly<T>(v1: T, v2: T): T {
return Math.random() <= 0.5 ? v1 : v2;
}
chooseRandomly<string>("勝ち", "負け");
chooseRandomly<number>(1, 2);
chooseRandomly<URL>(urlA, urlB);
→関数名の後ろに型変数をつける。
※<>の中の文字は何でも構いません。
→関数の引数の型にも型変数をつける。
17.ジェネリクスが使われている標準ライブラリ
ジェネリクスは標準ライブラリの中でも多くの箇所で利用されています。
ジェネリクスを利用する代表例
Arrayオブジェクト
const numbers: Array<number> = [1, 2, 3, 4];
// 又は、
const numbers: number[] = [1, 2, 3, 4];
Promiseオブジェクト
[詳細]h(ttps://book.yyts.org/features/promise-async-await)
Mapオブジェクト
→Map <K, V>
→K にキーの型を指定しV にキーに紐づく値の型を指定します。
→複数の型定義を持つことも可能です。
type Address = {
country: string,
postalCode: string,
address1: string,
};
const addresses = new Map<string, Address>();
addresses.set("太郎", {
country: "日本",
postalCode: "8256405",
address1: "東京都",
});
console.log(addresses.get("太郎"));
18.型パラメーターの制約
TypeScriptではジェネリクスの型パラメーターを特定の型に限定することができます。
ジェネリクス型パラメータの問題点
ジェネリクスの型は任意の型が指定可能なので、渡す型によっては指定したプロパティが存在しない場合があります。
// これはエラーになる
function changeBackgroundColor<T>(element: T) {
// error: プロパティ「style」はタイプ「T」に存在しません。
element.style.backgroundColor = 'red';
return element;
}
型パラメータに制約をつける
extendsキーワードを用いることでジェネリクスの型Tを特定の型に限定することができます。
function changeBackgroundColor<T extends HTMLElement>(element: T) {
element.style.backgroundColor = 'red';
return element;
}
インターフェースは実装はimplementsキーワードを使いますが、型パラメータに使うときはextendsを使います。
interface ValueObject<T> {
// .....
}
class UserID implements ValueObject<number> {
// .....
}
class Entity<ID extends ValueObject<unknown> {
// .....
}
19.デフォルト型パラメータ
関数の引数にデフォルト値を指定するように、ジェネリクスでもデフォルトの型パラメーターを指定することができます。
// <T>を<T = デフォルト型パラメータ>とする
type MyErrorEvent<T = Error> = {
error: T;
type: string;
}
// デフォルト型パラメータを指定した事で Error の型指定を省略できる
const errorEvent: MyErrorEvent = { error: new Error('エラーです'), type: 'syntax' }
const networkErrorEvent: MyErrorEvent<NetworkError> = { error: new NetworkError('ネットワークエラーです'), type: 'nextwork' }
型パラメーターの制約をして、かつ、デフォルト値を指定することもできます。
// 型TをErrorのサブクラスに限定しつつ、省略時はSyntaxErrorとする場合
type MyErrorEvant<T extends Error = SyntaxError> {
error: T;
type: string;
}
20.Promise/async/await
Promise: 非同期処理を見やすく書くことができます。
async/await: Promiseで書いたコードを更に見やすく書くことができます。
※次のドキュメントが非常に分かりやすくまとめて頂いているので、最初にこちらを読み進めてPromiseについて学ぶことをオススメします。
JavaScript Primer
Promiseとジェネリクス
→コールバック地獄を解消できます
注目
→request1()関数の戻り値をPromiseと型指定をしている
※Promiseのジェネリクスの型Tは必須
// 非同期でAPIにリクエストを投げて値を取得する処理
function request1(): Promise<number> {
return new Promise((resolve) => {
setTimeout(() => {
resolve(1);
}, 1000);
});
};
// 受け取った値を別のAPIにリクエストを投げて値を取得する処理
function request2(result1: number): Promise<number> {
return new Promise((resolve) => {
setTimeout(() => {
resolve(result1 + 1);
}, 1000);
});
};
// 受け取った値を別のAPIにリクエストを投げて値を取得する処理
function request3(result2: number): Promise<number> {
return new Promise((resolve) => {
setTimeout(() => {
resolve(result2 + 2);
}, 1000);
});
};
request1().then((result1) => {
return request2(result1);
}).then((result2) => {
request3(result2).then((result2) => {
console.log(result2);
})
});
async/await
関数の前にasyncキーワードをつけることで、更に簡単に書くことができます。
// asyncを使った場合
async function requestAsync(): Promise<number> {
return 1;
}
// asyncを使わない場合
function request(): Promise<number> {
return new Promise((resolve) => {
resolve(1);
});
}
requestAsync().then((result) => {
console.log(result); // -> 1
});
awaitはPromiseの値が解決されるまで実行を待機して、解決された値を返します。
※awaitはasync関数の中でのみ使えます。
function iti(): Promise<string> {
return new Promise((resolve) => {
setTimeout(() => {
resolve('hello');
}, 2000);
});
}
async function iii() {
console.log('before');
// この書き方はできない
// const result = await request();
// console.log(result);
iti().then(ll => {
console.log(ll);
});
const mama = await iti();
console.log(mama);
console.log('after');
}
iii();
console.log('finished');
21.ユーティリティ型(Utility Type)
型を付与するときにあらかじめ用意されている便利な型の表現がいくつかあります。
type Person = {
surname: string;
middleName?: string;
givenName: string;
};
type User = {
surname: string;
middleName?: string;
givenName: string;
age: number;
address?: string;
nationality: string;
createdAt: string;
updatedAt: string;
};
Partialの例
type User = {
surname: string;
middleName?: string;
givenName: string;
age: number;
address?: string;
nationality: string;
};
type Kkk = Partial<User>;
function ddd({
surname,
middleName,
givenName,
age,
address,
nationality
}: Kkk): Promise<User[]> {
//..
}
ddd({});
ddd({ age: 21 });
22.定義ファイル
npmなどの外部のパッケージを利用する場合は、型定義ファイルが含まれているとは限りません。
型宣言によるコードチェックが行えません。
型定義ファイルとは
アクセス可能な宣言を記述したファイル
拡張子: .d.ts
用途
パッケージを配布するために作成されます。
JavaScriptパッケージだけでは、型チェックなどができない
定義ファイルの有無
それぞれ、対処法が異なる
詳細:サバイバルTypeScript 定義ファイル
>定義ファイル有り
→TypeScriptで書かれたパッケージ
→JavaScriptで書かれたパッケージだが、 .d.tsファイルを同梱している
>定義ファイル有りだが別途インストールが必要
→JavaScriptで書かれたパッケージだが、Definitely Typedに登録されている
>定義ファイル無し
→JavaScriptで書かれたパッケージで定義ファイルが存在しない
23.tsconfig.json Deep Drive
詳細:サバイバルTypeScript: tsconfig.json Deep Dive
24.import / export / require
用途に適した出力に変えることができます。
かつてのJavaScript
→HTMLでの管理
→例えばjQueryのパッケージは、HTML内にscriptタグで宣言する
→jQueryに依存するパッケージはそれよりも下に書かなければいけない。
→読み込む順番が間違った場合、そのHTMLは動作しなくなるでしょう。
Node.js(npm)が登場してから
→使いたいパッケージをそのまま使える
CommonJS
//require()
//js(ts)ファイルを読み込む機能。
//※ファイル名は相対パス指定
const package1 = require('ファイル名');
//module.exports
//他のファイルを読み込むためには、そのファイルは何かを出力している必要があります。
module.exports = i => i + 1;
//exports
//...
ES Module
→フロントで採用されているファイル読み込み方法
※ES6で追加された機能
//import
// .js .tsファイル読み込み
// ※必ずファイルの一番上に書かないといけない
import * as package1 from 'package1';
// 又は
import package2 from 'package2';
//export default
//export
//import()
Node.jsでES Moduleを使う
CommonJSが長く使われてきましたが、ES Moduleもサポートが始まりました。
※ES Moduleを使う場合、少しの準備が必要になります。
TypeScriptでは
→ES Module方式の記法です。
→CommonJSかES Moduleかは、TypeScriptではあまり意識する機会は無いでしょう。
25.型変数(Type Variables)
型変数は、ジェネリクスで重要な概念です。
型変数
→変数に型を代入して、使い回しできます
function aaa<T>(value: T): T {
console.log(value);
return value;
}
型引数(type arguments)
→型変数に代入した型のこと。
// numberが型引数です
const value = bbb<number>(123);
→型推論が使えるので、型引数は省略できます。
const value = bbb(123);
型変数名の慣習
→T,U,Vを用いることが多い。(templateの略)
function fff<T, U>(a: T, b: U) { ... }
以上、ありがとうございました。