「プロを目指す人のためのTypeScript入門」の読書メモです。
TypeScript は JavaScript
に 静的型付け
を追加した言語です。
[!NOTE] コード内で Node.js を使用する場合(
require
など)は @type/node もインストールします。 逆を言えばコード内で Node.js を使用しない場合は @type/node は必要ありません。
どのバージョンの JavaScript ( ECMAScript )[^1] にトランスパイルするのかを ts.config の target プロパティで指定します。
[^1]: 例) es5, es2015, es2020 など。
[!NOTE] tsc に個別ファイルを指定した場合は ts.config を無視します(例:
$ npx tsc /path/to/file.ts
)。
1.
でトランスパイルした JavaScript を Node.js で実行( node )型推論の基本は式から型を推論します。
// 式 10 は number なので num の型は number (厳密には数値 `10` のリテラル型)
const num = 10;
// 式 test は string なので s の型は string(厳密には文字列 `test` のリテラル型
const s = 'test';
型
から関数式の内部(ここでは引数型)を推論(逆方向の型推論と呼ぶ)できる場合は型アノテーションを省略できます。
逆方向の型推論を contextual typing と呼びます。
type F = (value: string) => string;
// 引数の型アノテーションを省略する場合
const getName: F = (name) => return name;
// 引数の型アノテーションを省略しない場合
const getName: F = (name: string): string => return name;
TypeScript プログラムにおける値は、プリミティブと、あとに説明するオブジェクトの2種類に大別されます。 出典:プロを目指す人のためのTypeScript入門 p34
※ 関数も関数オブジェクトと呼ばれることからわかるようにオブジェクトです。
[^undefined]: JavaScript で存在しない プロパティ
にアクセスした場合は undefined
を返します。一方存在しない オブジェクト
にアクセスした場合はランタイムエラーになります。
[^function_type]: 関数もオブジェクトですが、型は function なのでリストを分けています。
文
はセミコロンで区切られて上から順に実行されます[^sentence]。
文
は 宣言
( declaration )とその他に分けられます。
例) 例えば(正式には) 変数宣言文とは呼ばす 変数宣言
、関数宣言文とは呼ばず 関数宣言
です。
[^sentence]: 制御構文、関数宣言( function Foo() {}
)の巻き上げ、type 文のコンパイル時チェックなどの例外があります。また行末のセミコロンは省略可能です。
式は一般に何らかの計算を表します。そして、その計算の結果が式の結果となるのです。
出典:プロを目指す人のためのTypeScript入門 p27
式文は、式のあとにセミコロンを書く文です。
文と式の決定的な違いは何でしょうか。それは結果があるかどうかです
出典:プロを目指す人のためのTypeScript入門 p27
/*
* 文の例
*/
// 文1 変数宣言
const hello = 'Hello';
// 文2 関数宣言
function getHello(name: string): string {
return `Hello ${name}!`;
}
function loggingHello(name: string): void {
console.log(`Hello ${name}!`);
}
/*
* 式
*/
// 例1
'Hello'
// 例2
3 + 5 // 式 + 式
// 例3(変数名も式であることに注意)
foo
/*
* 式文
*/
// 式文1 代入
message = 'Hello World'; // 代入演算子の左辺にある変数名( message )も式になる
// 式文2 戻り値のない関数呼び出し
loggingHello('Hiroshi');
ブロックとは、{ }の中に文をいくつでも書けるとう構文で、ブロック自体は1つの文として扱われます。ブロックを文として実行する場合、その中に書かれた文が上から順番に実行されます。
出典:プロを目指す人のためのTypeScript入門 p63
ブロックが文の一種であるということは、if (条件式) 文という構文の文のところにブロックを置くことができるということです。
出典:プロを目指す人のためのTypeScript入門 p63
複数の文を1つの文にまとめる 出典:プロを目指す人のためのTypeScript入門 p63
ブロックスコープの導入 出典:プロを目指す人のためのTypeScript入門 p63
リテラルとは、何らかの値を生み出すための式のことで、生み出したい値に応じていくつかの種類があります。
出典:プロを目指す人のためのTypeScript入門 p35
つまり リテラル
は TypeScript の 値
を生み出す式。 TypeScript の 値
は前述のとおり オブジェクト
と プリミティブ
に大別されます。
x == null
は x が null
か undefined
のときのみ true になります。
null
が良くて undefined
は駄目な場合は x === null
を使います 。
x === NaN は x がどのような値でも( NaN であっても)必ず false になります。
NaN を判定したいときは Number.isNaN()
を使用します。
x ?? y
は x が null または undefined のときのみ y を返します。出典:プロを目指す人のためのTypeScript入門 p56
x || y
は x が 0 や 空文字や false の場合も y を返します。
簡潔にまとめると部分型は親の代替ができる型のことを表す。
型Sと型Tがオブジェクト型だとして、次の2つの条件が満たされればSがTの部分型になります。
- Tが持つプロパティはすべてSにも存在する。
- 要件1の各プロパティについて、Sにおけるそのプロパティの型はTにおけるプロパティの方の部分型(または同じ型)である。
出典;プロを目指す人のためのTypeScript入門 p97
type 文は オブジェクト型
だけでなく プリミティブな型
の別名
(型名
)を作成できます。
type文は決して「新たに型を作って利用可能にする」ものではなく、「すでにある型に別名をつける」だけのもの
出典:プロを目指す人のためのTypeScript入門 p89
// オブジェクト型
type MyObject = {
name: string;
age: string;
};
// string 型
type MyString = string;
// 型チェックでエラー
const myString: MyString = 28; // Type 'number' is not assignable to type 'string'.
// ※ JavaScript は変数の大文字・小文字を区別します。かつ型名、変数名は別の名前空間です(なので 重複する名前の型名と変数名が共存できます)。
type
文による型宣言はその型名の使用より後でも問題ありません(型チェックはコンパイル時に実行されるためです)。
[^interface]:interface 宣言
で作成できる型名は オブジェクト型
のみです。多くのの場合は type 文
で代用可能です。
型引数は、型を定義するときにパラメータをもたせることができるというもので、ジェネリクスに少し似ています。
出典:プロを目指す人のためのTypeScript入門 p100ジェネリクス(generics)とは、型引数を受け取る関数を作る機能のことです。
出典:プロを目指す人のためのTypeScript入門 p168
type Family<Parent, Child> = {
mother: Parent;
father: Parent;
child: Child;
};
const family: Family<number, string> = {
mother: 0,
father: 100,
child: "1000"
};
type OtherFamily = Family<string, string>;
const otherFamily: OtherFamily = {
mother: "0",
father: "100",
child: "1000"
}
適切な数の型引数を指定せずに型を使用した場合はコンパイルエラーという結果になります。 出典:プロを目指す人のためのTypeScript入門 p101
// エラー: Generic type 'Family' requires 2 type argument(s).
const family: Family = {
mother: 0,
father: 100,
child: "1000",
}
type 文において型引数を宣言するとき、extends という構文を使うことができます。具体的には、型引数の宣言の後ろに extends 型を付加することができます。この構文は、「この型引数は常に型の部分型でなければならない」という制約(constraint)を意味します。 出典:プロを目指す人のためのTypeScript入門 p101
type HasName = {
name: string;
};
type Family<Parent extends HasName, Child extends HasName> = {
mothier: Parent;
father: Parent;
child: Child;
};
TypeScriptにはイテレータ(Iterator)という概念が存在します。 ... イテレータは繰り返し処理のための汎用的なインターフェースです。イテレータを通じて繰り返し処理ができる値のことをJavaScript用語でIterableと呼びます。for-of文のofの右の式には、厳密には配列だけでなくそれ以外のIterableな値を与えることができまるのです。 出典:プロを目指す人のためのTypeScript入門 p111)
より具体的に言うと、イテレーターは、次の 2 つのプロパティを持つオブジェクトを返す next() メソッドを持つことによってイテレータープロトコルを実装するオブジェクトです。value
反復シーケンスの次の値.done
シーケンスの最後の値が既に消費されている場合に true となります。done と並んで value が存在する場合、それがイテレーターの戻り値となります。
出典:イテレーターとジェネレーター
参考:Generator
/*
* ジェネレーターはイテレータープロトコルを実装している
*/
function* createIterator() {
const limit = 10;
for (let i = 0; i < limit; i++ ) {
yield i;
}
}
const iterator = createIterator();
for (const value of iterator) {
console.log(value);
}
/*
* ジェネレーターはイテレータープロトコルを実装しているので `next()` を持っており以下のようにも書けます。
*/
const otherIterator = createIterator();
while(true) {
const result = otherIterator.next();
if ( result.done ) {
break;
}
console.log(result.value)
}
const one = {
name: 'John',
age: 30,
}
const other = {
hobby: 'Reading',
...one,
}
console.log(other);
// {
// "hobby": "Reading",
// "name": "John",
// "age": 30
// }
// typeof キーワードで動的に型名作成
type Other = typeof other;
// type Other = {
// name: string;
// age: number;
// hobby: string;
// }
typeof には typeof キーワードと typeof 演算子の 2 種類あります。混同しないように注意が必要です。
[^typeof]: typeof null が object
になることに注意してください(歴史的経緯)。
オブジェクトのプロパティの中身をプロパティと同名の変数に入れたい場合にしかこのパターンを用いることができません。
出典:プロを目指す人のためのTypeScript入門 p114
const rect = {width: 100, height: 200, depth: 300};
const {width, height, depth} = rect;
console.log(width, height, depth);
// 100, 200, 300
ref. https://typescript-jp.gitbook.io/deep-dive/future-javascript/destructuring
分割を使用して構造体の深いデータを取得
出典: https://typescript-jp.gitbook.io/deep-dive/future-javascript/destructuring
const page = {
title: 'Hello World',
content: {
catchCopy: 'HELLO WORLD',
lead: 'Welcome to my page.',
body: 'This is content'
}
}
var {content: {catchCopy}} = page;
console.log(catchCopy);
// HELLO World
console.log(content);
// ERR content is not defined
var { content } = page;
console.log(content);
//
{
body: "This is content",
catchCopy: "HELLO WORLD",
lead: "Welcome to my page."
}
content
を foo
に代入します。
const page = {
title: 'Hello World',
content: {
catchCopy: 'HELLO WORLD',
lead: 'Welcome to my page.',
body: 'This is content'
}
}
const {content: foo} = page;
console.log(foo);
// {
// "catchCopy": "HELLO WORLD",
// "lead": "Welcome to my page.",
// "body": "This is content"
// }
const one = {
foo: 'a',
bar: 'b',
baz: 'c',
};
const other = {...one};
console.log(other);
// {
// "foo": "a",
// "bar": "b",
// "baz": "c"
// }
one.foo = 'x';
console.log(other.foo); // a
const one = {
foo: 'a',
bar: 'b',
baz: 'c',
};
const {...other} = one;
console.log(other);
// {
// "foo": "a",
// "bar": "b",
// "baz": "c"
// }
one.foo = 'x';
console.log(other.foo); // a
TypeScript は return しない関数の戻り値を undefined とみなします。。
オプショナルな引数の型は undefine とのユニオン型になります。
// オプショナルな引数の型は undefine とのユニオン型になる
// (parameter) a: string | undefined
function foo(a?: string){
// 呼び出しで引数が省略されたときの a は undefined
if (a) {
console.log(a)
} else {
console.log('省略')
}
}
foo('test');
// test
foo();
// 省略
/*
* オプショナルではない引数が省略されたらコンパイルエラー
*/
function bar(a: string){
// 呼び出しで引数が省略されたときの a は undefined
if (a) {
console.log(a)
} else {
console.log('省略')
}
}
bar();
// Expected 1 arguments, but got 0.
関数型宣言: type 型名 = (引数名: 型名) => 戻り値型
type User = {
name: string;
age: number;
}
// 関数型の型を明記
type GetNameFunc = (user: User) => string;
const getName: GetNameFunc = (user: User): string => {
return user.name;
}
console.log(getName({ name: 'John', age: 30 })); // John
/*
* コンパイル時の型チェックでエラー
* // 関数の型チェックエラー文
* > Type '(name: string) => string' is not assignable to type 'GetNameFunc'.Types of parameters 'name' and 'user' are incompatible.
*
* // 呼び出し時の型チェックのエラー文
* > Type 'User' is not assignable to type 'string'. const getNameFaulty: GetNameFunc = (name: string):string => {
* return name;
* }
*/
console.log(getNameFaulty('jhon')) // 文字型を渡しているので型チェックエラー
ジェネリクス(generics)とは型引数を受け取る関数を作る機能のことです。
出典:プロを目指す人のためのTypeScript入門 p168
// 出典:プロを目指す人のためのTypeScript入門 p169
function repeat <T>(elem: T, num: number): T[] {
const result: T[] = [];
for (let i = 0; i < num; i++ ) {
result.push(elem)
}
return result;
}
console.log(repeat('a', 5)); // ["a", "a", "a", "a", "a"]
console.log(repeat(123, 3)); // [123, 123, 123]
// 関数の型名をジェネリクスで定義
type Echo<T> = (value: T) => T;
const echoString: Echo<string> = (str: string) => {
return str;
}
const echoNumber: Echo<number> = (num: number) => {
return num;
}
console.log(echoString('Hello')); // Hello
console.log(echoNumber(123)); // 123
以下のように簡潔にかけます。
const echo = <T>(value:T): T => {
return value;
}
console.log(echo('Hello'));
console.log(echo(123));
todo
結果を表示する
type MyCallback<T> = (value: T[]) => T[];
const caller = <T>(callback: MyCallback<T>, args: T[]): T[] => {
return callback(args);
}
const result = caller((nums: number[]) => {
return nums.map(num => num * 2);
}, [1, 2, 3]);
console.log(result); // 2 4 6
親と代替できることが重要です。
より少ない入力(引数)からより多い出力(戻り値)を返します。
出典:プロを目指す人のためのTypeScript入門 p165
型
から関数式の内部(ここでは引数型)を推論(逆方向の型推論と呼ぶ)できる場合は型アノテーションを省略できます。
逆方向の型推論を contextual typing と呼びます。
type F = (value: string) => string;
// 引数の型アノテーションを省略する場合
const getName: F = (name) => return name;
// 引数の型アノテーションを省略しない場合
const getName: F = (name: string): string => return name;
クラス宣言の重要な特徴のひとつは、クラスオブジェクトという値を作るものであると同時に、インスタンスの型を宣言するものであるということです。
出典:プロを目指す人のためのTypeScript入門 p201
名前には2種類あることを理解する必要があります。すなわち、変数名と型名です。これらは別々の名前空間に属しています。
出典:プロを目指す人のためのTypeScript入門 p203
class User {
name: string;
age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
}
const user1 = new User('user1', 18);
// user1 は User のインスタンス
console.log(user1 instanceof User) // true
// class User { } で User 型が定義されていることに注意
const user2: User = {
name: 'user2',
age: 19
}
// user2 は User 型として扱えるが User のインスタンスではない
// {} は new Object の糖衣構文なので Object もインスタンスになる
console.log(user2 instanceof User) // false
todo console.log(user2 instanceof Object) // true
// typeof 演算子は object
console.log(typeof user1, typeof user2); // "object", "object"
クラスについて MDN に以下のように記載されています。
JS のクラスはプロトタイプに基づいて構築されていますが、一部の構文や意味はクラスに固有です。
出典:https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Classes
「一部の構文や意味はクラスに固有です」との記載があるのでクラスが ES 5 のプロトタイプベースの糖衣構文と言い切れるかはわかりません。
class User {
name: string;
age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
}
/*
* TypeScript は JavaScipt のスーパセットなので prototype 継承も有効
*/
// new User() でインスタン( user1 )を作成
const user1 = new User('Jhon', 25);
// インスタンス( user1 )はコンストラクタ( User )の prototype へのリンクを持つ
console.log(User.prototype === Object.getPrototypeOf(user1)); // true
console.log(user1.constructor === User); // true
const user2: User = {
name: 'Jhon',
age: 25
}
// user2 は( User 型のオブジェクトだが)User のインスタンスではない
// ↑より User.prototype へのリンクは持たない
console.log(User.prototype === Object.getPrototypeOf(user2)); // false
console.log(user2.constructor === User); // false
// user2 は Object のインスタンス(オブジェクトリテラル {} は new Object の糖衣構文)
// ↑より user2 は Object.protype へのリンクを持つ
console.log(Object.prototype === Object.getPrototypeOf(user2)); // true
console.log(user2.constructor === Object); // true
クラスのメソッドは protoype のメソッドになる。
class Product {
#name: string;
#price: number;
constructor(name: string, price: number) {
this.#name = name;
this.#price = price;
}
getOrder(num: number): string {
return `${this.#name} is ${this.#price * num}`
}
}
const product1 = new Product('product1', 100);
const product2 = new Product('product2', 200);
console.log(typeof product1.getOrder, typeof product2.getOrder); // function, function
// どちらも同じメソッド( Product.prototype.getOrder )を参照
console.log(product1.getOrder === product2.getOrder); // true
console.log(product1.getOrder === Product.prototype.getOrder); // true
console.log(product2.getOrder === Product.prototype.getOrder); // true
また、コンストラクタもオーバーライドすることができます。ただし、その場合は子クラスのコンストラクタの引数の中にsuper呼び出しを含める必要があります。
プロを目指す人のためのTypeScript入門 p212
クラスのメソッドは prototype に定義されます。
プロパティはインスタンスのプロパティになります。
class Product {
#name: string;
#price: number;
constructor(name: string, price: number) {
this.#name = name;
this.#price = price;
}
getOrder(num: number): string {
return `${this.#name} is ${this.#price * num}`
}
}
const product1 = new Product('product1', 1000);
const product2 = new Product('product2', 2000);
console.log(typeof product1.getOrder, typeof product2.getOrder); // function, function
console.log(product1.getOrder === product2.getOrder); // true
console.log(product1.getOrder === Product.prototype.getOrder); // true
console.log(product2.getOrder === Product.prototype.getOrder); // true
// メソッドは prototype ベースなので Production.prototype.getOrder を Function.prototype.apply() で呼び出すこともできる
console.log(Product.prototype.getOrder.apply(product1, [2])); // 2000
console.log(typeof product1.getOrder); // function
// なので Function.prototype.apply() を使用できる
console.log(product1.getOrder.apply(product2, [2])); // this に production2 を指定しているので 4000 になる
// typescript
class Foo {
public x: number;
public echo: (x:number) => number;
constructor(x:number) {
this.x = x;
// インスタンスメソッドを定義
this.echo = x => x
};
// プロトタイプベースのメソッド定義
double(): number {
return this.x**2
}
}
const foo1 = new Foo(3);
foo1.double();
ts.config の target
を es5 にしてトランスパイルされたコード。
"use strict";
// JavaScript
var Foo = /** @class */ (function () {
function Foo(x) {
this.x = x;
// インスタンスメソッドを定義
this.echo = function (x) { return x; };
}
;
// プロトタイプベースのメソッド定義
Foo.prototype.double = function () {
return Math.pow(this.x, 2);
};
return Foo;
}());
var foo1 = new Foo(3);
foo1.double();
例外とは、ランタイムエラーのことです。
プロを目指す人のためのTypeScript入門 p231
エラーを発生させたいとき、普通はまずエラーを表すオブジェクトを用意します。エラーを表すオブジェクトとは、Errorのインスタンスです。
出典:プロを目指す人のためのTypeScript入門 p231
finallyブロックの内容はエラーが発生してもしなくても実行されます。
出典:プロを目指す人のためのTypeScript入門 p238
コンパイル時の型チェック
でエラーを発生させるundefined
を返す※ 存在しないオブジェクトのプロパティにアクセスした場合は JavaScript はランタイムエラーを発生させます。
TypeScript は オプショナルチェイン
を使ってオブジェクトが存在しない場合の処理をスキップできます。
通常の型推論は「式からその式自体の型が推論される」という挙動を指します。
式の型が先にわかっている場合に、それをもとに式の内部に対して推論が働くことをさします。
出典:プロを目指す人のためのTypeScript入門 p157
JavaScript
は null
や undefined
なオブエクトに対するプロパティアクセスはランタイムエラーになります。
例: obj?.prop
// または obj?.['age']
一方で obj?.prop の場合、obj が null や undefined の場合でもランタイムエラーは発生せず、結果はundefinedとなります。 出典:プロを目指す人のためのTypeScript入門 p260
?.から続く、まとめて飛ばされるひとまとまりの部分をオプショナルチェイン(optional chain)と呼びます。 出典:プロを目指す人のためのTypeScript入門 p263
リテラル型はプリミティブ型をさらに細分化した型です。例えば 、 "foo" という型(文字列リテラル型ではく型です!)が存在し、これは一種のリテラル型(その中でも文字列のリテラル型)です。 出典:プロを目指す人のためのTypeScript入門 p263
// これは"foo"という文字列のみが属するリテラル型
type FooString = "foo";
// これは OK
const foo: FooString = "foo";
// あまり意味はないが以下のようにも書ける
const foo: "foo" = "foo";
// エラー: Type "bar" is not assignable to type '"foo2"'.
const bar: FooString = "bar";
const foo: "foo" = "foo";
const one: 1 = 1;
const t: true = true;
const three: 3n = 3n;
また、リテラル型は、我々が明示的に書かなくても型推論によって登場します。実は、(値としての)"foo" や 26 といったリテラルをプログラム中に書くと、これらの式の型としてリテラル型が推論されます。よって、リテラルを変数に代入することによって、その変数はリテラル型を得ることになります。
// 変数uhyoNameは"uhyo"型 const uhyoName = "uhyo"; // 半数ageは26型 const age = 26; 出典:プロを目指す人のためのTypeScript入門 p264
type StringHelloLiteral = `Hello, ${string}`;
type NumberHelloLiteral = `Hello, ${number}`;
const stringValue = 'Taro';
const numberValue = 26;
const stringHello: StringHelloLiteral = `Hello, ${stringValue}`;
const numberHello: NumberHelloLiteral = `Hello, ${numberValue}`;
console.log(stringHello, numberHello);
型の絞り込みは、コントロールフロー解析(control flow analysis)と呼ばれることもあります。 出典:プロを目指す人のためのTypeScript入門 p271
強力な型システムを持つプログラム言語はよく代数型データ型(algebraic data type ADT)の機能を持っています。 これはいくつかの種類に分類されるデータを表すための型・データ構造で、タグ付きユニオン(tagged uniton) や直和といった別名もあります。TypeScriptには代数的データ型の機能がありませんが、オブジェクト型とユニオン型を用いて擬似的に代数データ型を再現することができます。 出典:プロを目指す人のためのTypeScript入門 p274
扱うデータの形と可能性を型で正確に表現する
type Animal = {
tag: "animal"; // 文字列 "animal" のリテラル型
species: string;
}
type Human = {
tag: "human";
name: "string";
}
type User = Animal | Human
function getUserName(user: User): striing {
switch(user.tag) {
case "human":
return user.name
case
return "名無し";
}
}
type Human = {
type: "human";
name: string;
age: number;
};
function setAge(human: Human, age: Human["age"]) {
return {
...human,
age
}
}
const uhyo: Human = {
type: "human",
name: "uhyo",
age: 26
};
const uhyo2 = setAge(uhyo, 27);
conosle.log(uhyo2);
keyof 型は、オブジェクト型からそのオブジェクトのプロパティ名の型を得る機能です。具体的には、keyof型は型Tに対してkeyof T と書きます。
プロパティが複数ある場合は、このようにそれらすべてのユニオン型となります。 出典:プロを目指す人のためのTypeScript入門 p280
重要:「プロパティが複数ある場合は、このようにそれらすべてのユニオン型となります」
function get<T, K extends keyof T>(obje: T, key: K): T[K] {
return obj[key];
}
type Human = {
name: string;
age: number;
}
const uhyo: Human = {
name: "uhyo",
age: 26
};
// uhyoName は string 型
const uhyoName = get(uhyo,, "name");
// uhyoAge は number 型
const uhyoAge = get(uhyo, "age");
keyof T
は keyof 型で具体的にはユニオン型 "name" | "age"
K extends keyof T
はユニオン型 "name" | "age"
の部分型extends keyof T
を省略すると戻り型 T[K]
および関数内の obje[key]
が Tのプロパティ( obje のプロパティ)であることが保証できない型アサーションは式 as 型という構文で、その式の型を強制的に変えるという意味です。 .... 型アサーションでは、実際の「値」に対しては何も起こらずに、TypeScriptコンパイラが認識する「型」だけが変化します。 出典:プロを目指す人のためのTypeScript入門 p286
上記より型アサーションに誤りがあるとランタイムでエラーが発生します。
なので「型アサーションの使用はできるだけ避けるべき」(出典:プロを目指す人のためのTypeScript入門 p286 )です。
ユーザー定義型ガードとは戻り値に型述語が書かれた関数です。
ユーザー定義型ガード(user-defined type guards)とは、型の絞り込みを自由に行うためのしくみです。 出典:プロを目指す人のためのTypeScript入門 p299
ユーザー定義型ガードは、返り値の型として型述語(type predicates)が書かれた特殊な関数です。型述語には2種類の形があります。 出典:プロを目指す人のためのTypeScript入門 p299
// 出典:プロを目指す人のためのTypeScript入門 p299
function isStringOrNumber(value: unknown): value is string | number {
return typeof value === "string" || typeof value === "number";
}
const something: unknown = 123;
if (isStringOrNumber(something)) {
// ここではsomethingは string | number 型
console.log(something.toString();
}
Node.js でモジュールシステム ES Modules を使用するための設定を記載します。
Node.js
: package.json
の type フィールドに module
を指定するcommonjs
TypeScript
module コンパイラオプション[^ts-compiler-option]でモジュールシステムを指定するTypeScript
:moduleResolution コンパイラオプションで node
や nodenext
を指定すると import にパス( ./relative/path.js )ではなくモジュール名(例 express, jquery )が設定されると外部モジュールとみなす※ target コンパイルオプションはどのバージョンの JavaScript にトランスバイルするかを指定します。設定ちは es5, es6/es2015, es2024, exnext などです。exnext は TypeScript がサポートしている最新のターゲットバージョンを参照します。 ref. https://www.typescriptlang.org/tsconfig/#target
[^ts-compiler-option]: ts.config の module プロパティでも指定可能(一般的)。
1900-01-01T00:00:00+09:00
というフォーマットfunction foo () {
//...
return
a + b
}
// return の後にセミコロンが追加さえるのでコンパイルエラーが発生します。
ambient: 環境
JavaScriptコードを生成せず、型推論器にだけ情報を渡すのに使われるのが アンビエント宣言 (または環境宣言; ambient declaration) です。 declare のついた宣言がアンビエント宣言になります。 (declare なのに呼び名が「アンビエント」なのは不思議ですが、declareは「宣言する」という意味なので仕方なさそうです)