From 66ff311faf11cf134b6546eff31202aff898e06b Mon Sep 17 00:00:00 2001 From: TAKAHASHI Shuuji Date: Wed, 18 Dec 2019 06:36:04 +0900 Subject: [PATCH 01/35] Update code in /docs/types/type-system.md. --- docs/types/type-system.md | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/docs/types/type-system.md b/docs/types/type-system.md index 613d0ea61..e4783a353 100644 --- a/docs/types/type-system.md +++ b/docs/types/type-system.md @@ -221,23 +221,14 @@ function formatCommandline(command: string[]|string) { ```ts function extend(first: T, second: U): T & U { - let result = {}; - for (let id in first) { - result[id] = first[id]; - } - for (let id in second) { - if (!result.hasOwnProperty(id)) { - result[id] = second[id]; - } - } - return result; + return { ...first, ...second }; } -var x = extend({ a: "hello" }, { b: 42 }); +const x = extend({ a: "hello" }, { b: 42 }); // x now has both `a` and `b` -var a = x.a; -var b = x.b; +const a = x.a; +const b = x.b; ``` ## タプル型 From 3e3949ef763cdadfeb748cfc3d773b95ed078be2 Mon Sep 17 00:00:00 2001 From: TAKAHASHI Shuuji Date: Thu, 19 Dec 2019 10:13:03 +0900 Subject: [PATCH 02/35] Add a new section in to docs/types/migrating.md. --- docs/types/migrating.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/types/migrating.md b/docs/types/migrating.md index 28aed5973..6989f1595 100644 --- a/docs/types/migrating.md +++ b/docs/types/migrating.md @@ -111,3 +111,6 @@ declare module "*.css"; ```ts declare module "*.html"; ``` + +# More +If you want to be more silent about your upgrade because you couldn't get team buy in to move to TypeScript, [TypeScript has a blog post on upgrading silently without having to convince your team up front](https://devblogs.microsoft.com/typescript/how-to-upgrade-to-typescript-without-anybody-noticing-part-1/). From e8609bee6f823ab4dcc7dea2c02042e9d79d236b Mon Sep 17 00:00:00 2001 From: TAKAHASHI Shuuji Date: Thu, 19 Dec 2019 10:17:10 +0900 Subject: [PATCH 03/35] Translate migrating.md. --- docs/types/migrating.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/types/migrating.md b/docs/types/migrating.md index 6989f1595..8ae0d91a1 100644 --- a/docs/types/migrating.md +++ b/docs/types/migrating.md @@ -112,5 +112,6 @@ declare module "*.css"; declare module "*.html"; ``` -# More -If you want to be more silent about your upgrade because you couldn't get team buy in to move to TypeScript, [TypeScript has a blog post on upgrading silently without having to convince your team up front](https://devblogs.microsoft.com/typescript/how-to-upgrade-to-typescript-without-anybody-noticing-part-1/). +# その他 + +もしチームがTypeScriptへの移行に積極的でなくて、もっと静かにアップグレードしたいときは、[チームを説得せずに気づかれずにアップグレードする方法について、TypeScriptチームがブログ記事を書いています](https://devblogs.microsoft.com/typescript/how-to-upgrade-to-typescript-without-anybody-noticing-part-1/)。 From 14bf5b0fbac464004fbaabbedad7a28183eba8a0 Mon Sep 17 00:00:00 2001 From: TAKAHASHI Shuuji Date: Thu, 19 Dec 2019 10:44:28 +0900 Subject: [PATCH 04/35] Update code in docs/enums.md and fix an error message. --- docs/enums.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/docs/enums.md b/docs/enums.md index 0190b7ef9..8ca8624e3 100644 --- a/docs/enums.md +++ b/docs/enums.md @@ -104,14 +104,16 @@ enum AnimalFlags { ここでは、左シフト演算子を使用して、特定のビットレベルに1を移動することにより、ビット単位の「0001」、「0010」、「0100」および「1000」になります(これらは10進数の1、2、4、8です。興味があれば)。ビット演算子`|`(or)/`&`(and)/`~`(not)は、ビットフラグを使って作業するときの友達です。 ```ts - enum AnimalFlags { None = 0, HasClaws = 1 << 0, CanFly = 1 << 1, } +type Animal = { + flags: AnimalFlags +} -function printAnimalAbilities(animal) { +function printAnimalAbilities(animal: Animal) { var animalFlags = animal.flags; if (animalFlags & AnimalFlags.HasClaws) { console.log('animal has claws'); @@ -124,7 +126,7 @@ function printAnimalAbilities(animal) { } } -var animal = { flags: AnimalFlags.None }; +let animal: Animal = { flags: AnimalFlags.None }; printAnimalAbilities(animal); // nothing animal.flags |= AnimalFlags.HasClaws; printAnimalAbilities(animal); // animal has claws @@ -286,4 +288,4 @@ enum Color { } ``` -注意しなければならないのは、前の定義(つまり、`0`、`1`、...)を除外するために、列挙の最初のメンバ(ここでは`DarkRed = 3`)を再初期化しないといけないことです。それを行わない場合は、TypeScriptは警告します(エラーメッセージ:`In an enum with multiple declarations, only one declaration can omit an initializer for its first enum element`)。 +注意しなければならないのは、前の定義(つまり、`0`、`1`、...)を除外するために、列挙の最初のメンバ(ここでは`DarkRed = 3`)を再初期化しないといけないことです。それを行わない場合は、TypeScriptは警告します(エラーメッセージ:`In an enum with multiple declarations, only one declaration can omit an initializer for its first enum element.`)。 From 15646124fa72e38d90203f34c9d24c2c3018c32f Mon Sep 17 00:00:00 2001 From: TAKAHASHI Shuuji Date: Thu, 19 Dec 2019 16:34:50 +0900 Subject: [PATCH 05/35] Undo translation for 'scripthost' because it's an argument option. --- docs/types/lib.d.ts.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/types/lib.d.ts.md b/docs/types/lib.d.ts.md index 6a00f4278..d215abfc9 100644 --- a/docs/types/lib.d.ts.md +++ b/docs/types/lib.d.ts.md @@ -249,7 +249,7 @@ libsは次のように分類できます。 * dom     * dom.iterable     * webworker -    * スクリプトホスト +    * scripthost * ESNext By-Featureオプション(バルク機能よりも小さい)     * es2015.core     * es2015.collection From 294e8944bd2edd341e6d353b347f24cdc20eb3c5 Mon Sep 17 00:00:00 2001 From: TAKAHASHI Shuuji Date: Fri, 20 Dec 2019 14:39:50 +0900 Subject: [PATCH 06/35] Add 'Declaring Functions' section. --- docs/types/functions.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/docs/types/functions.md b/docs/types/functions.md index 1df74f9f8..b0fffef05 100644 --- a/docs/types/functions.md +++ b/docs/types/functions.md @@ -140,3 +140,25 @@ padding(1,1,1); // Error: Not a part of the available overloads > TypeScriptの関数オーバーロードにランタイムでのオーバーヘッドはありません。関数が呼び出されると予想される方法を文書化し、コンパイラがコードの残りの部分をチェックするだけです。 +### Declaring Functions +> Quick Tip: *Type Declarations* are how you describe the types of existing implementations. + +There are two ways to *declare* the type of a function without providing an implementation. E.g. + +```ts +type LongHand = { + (a: number): number; +}; + +type ShortHand = (a: number) => number; +``` +The example above are both *exactly* equivalent. The differences exist when you want to add overloads. You can only add overloads in the long hand declaration version e.g. + +```ts +type LongHandAllowsOverloadDeclarations = { + (a: number): number; + (a: string): string; +}; +``` + +[](### Type Compatibility) From 26b32712c063b5558dd8ac0452e238750f7a0d93 Mon Sep 17 00:00:00 2001 From: TAKAHASHI Shuuji Date: Fri, 20 Dec 2019 14:50:31 +0900 Subject: [PATCH 07/35] Translate 'Declaring Functions' and remove a unnecessary anchor. --- docs/types/functions.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/types/functions.md b/docs/types/functions.md index b0fffef05..5edd05c94 100644 --- a/docs/types/functions.md +++ b/docs/types/functions.md @@ -140,10 +140,11 @@ padding(1,1,1); // Error: Not a part of the available overloads > TypeScriptの関数オーバーロードにランタイムでのオーバーヘッドはありません。関数が呼び出されると予想される方法を文書化し、コンパイラがコードの残りの部分をチェックするだけです。 -### Declaring Functions -> Quick Tip: *Type Declarations* are how you describe the types of existing implementations. +### 関数の宣言 -There are two ways to *declare* the type of a function without providing an implementation. E.g. +> 簡単なヒント: *型の定義*とは、既存の実装に対してあなたが型をどのように書くかということです。 + +具体的な実装を示さずに関数の型を*宣言する*方法には、2つの方法があります。以下に例を示します。 ```ts type LongHand = { @@ -152,7 +153,8 @@ type LongHand = { type ShortHand = (a: number) => number; ``` -The example above are both *exactly* equivalent. The differences exist when you want to add overloads. You can only add overloads in the long hand declaration version e.g. + +上の2つの例は*完全に*同じ宣言です。違いがあるのは、関数のオーバーロードを行おうとする場合です。前者の長い書き方の宣言で定義したときのみ、以下のようにオーバーロードを追加できます。 ```ts type LongHandAllowsOverloadDeclarations = { @@ -160,5 +162,3 @@ type LongHandAllowsOverloadDeclarations = { (a: string): string; }; ``` - -[](### Type Compatibility) From 84d2a105ace9e8c33d9a898dc774b25dc3460319 Mon Sep 17 00:00:00 2001 From: TAKAHASHI Shuuji Date: Sat, 21 Dec 2019 13:56:15 +0900 Subject: [PATCH 08/35] Fix the length of indentations. --- docs/types/freshness.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/types/freshness.md b/docs/types/freshness.md index 919aa448f..52f43c4d6 100644 --- a/docs/types/freshness.md +++ b/docs/types/freshness.md @@ -81,8 +81,8 @@ Freshnessの概念を使用する場合は、すべてのメンバーをオプ ```ts // Assuming interface State { - foo?: string; - bar?: string; + foo?: string; + bar?: string; } // You want to do: From d3754680ef9d66d7b58991b848e10c46c78ebc6f Mon Sep 17 00:00:00 2001 From: TAKAHASHI Shuuji Date: Sat, 21 Dec 2019 14:12:51 +0900 Subject: [PATCH 09/35] Update docs/types/typeGuard.md. --- docs/types/typeGuard.md | 66 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 65 insertions(+), 1 deletion(-) diff --git a/docs/types/typeGuard.md b/docs/types/typeGuard.md index f41274e0f..18a7f8ba4 100644 --- a/docs/types/typeGuard.md +++ b/docs/types/typeGuard.md @@ -99,11 +99,29 @@ function doStuff(q: A | B) { ### リテラル型のType Guard +You can use `===` / `==` / `!==` / `!=` to distinguish between literal values + +```ts +type TriState = 'yes' | 'no' | 'unknown'; + +function logOutState(state:TriState) { + if (state == 'yes') { + console.log('User selected yes'); + } else if (state == 'no') { + console.log('User selected no'); + } else { + console.log('User has not made a selection yet'); + } +} +``` + +This even works when you have literal types in a union. You can check the value of a shared property name to discriminate the union e.g. + あなたがユニオン型にリテラル型を持っているとき、それらをチェックして区別することができます。 ```ts type Foo = { - kind: 'foo', // Literal type + kind: 'foo', // Literal type foo: number } type Bar = { @@ -123,6 +141,18 @@ function doStuff(arg: Foo | Bar) { } ``` +### null and undefined with `strictNullChecks` + +TypeScript is smart enough to rule out both `null` and `undefined` with a `== null` / `!= null` check. For example: + +```ts +function foo(a?: number | null) { + if (a == null) return; + + // a is number now. +} +``` + ### ユーザー定義のType Guard JavaScriptには非常に豊富な実行時の解析サポートが組み込まれていません。単純なJavaScriptオブジェクトだけを使用している場合(構造型を使用する場合)、 `instanceof`または`typeof`にアクセスすることさえできません。これらの場合、Type Guard関数をユーザが定義することができます。これは、`someArgumentName is SomeType`を返す関数です。次に例を示します。 @@ -164,3 +194,37 @@ function doStuff(arg: Foo | Bar) { doStuff({ foo: 123, common: '123' }); doStuff({ bar: 123, common: '123' }); ``` + +### Type Guards and callbacks + +TypeScript doesn't assume type guards remain active in callbacks as making this assumption is dangerous. e.g. + +```js +// Example Setup +declare var foo:{bar?: {baz: string}}; +function immediate(callback: ()=>void) { + callback(); +} + + +// Type Guard +if (foo.bar) { + console.log(foo.bar.baz); // Okay + functionDoingSomeStuff(() => { + console.log(foo.bar.baz); // TS error: Object is possibly 'undefined'" + }); +} +``` + +The fix is as easy as storing the inferred safe value in a local variable, automatically ensuring it doesn't get changed externally, and TypeScript can easily understand that: + +```js +// Type Guard +if (foo.bar) { + console.log(foo.bar.baz); // Okay + const bar = foo.bar; + functionDoingSomeStuff(() => { + console.log(bar.baz); // Okay + }); +} +``` From 8c49a11f65aa2f4f285ffba7e0400920e9a6f78a Mon Sep 17 00:00:00 2001 From: TAKAHASHI Shuuji Date: Sat, 21 Dec 2019 14:16:59 +0900 Subject: [PATCH 10/35] =?UTF-8?q?Translate=20English=20sentences=20in=20th?= =?UTF-8?q?e=20section=20'=E3=83=AA=E3=83=86=E3=83=A9=E3=83=AB=E5=9E=8B?= =?UTF-8?q?=E3=81=AEType=20Guard'.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/types/typeGuard.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/docs/types/typeGuard.md b/docs/types/typeGuard.md index 18a7f8ba4..16eff0bae 100644 --- a/docs/types/typeGuard.md +++ b/docs/types/typeGuard.md @@ -99,7 +99,7 @@ function doStuff(q: A | B) { ### リテラル型のType Guard -You can use `===` / `==` / `!==` / `!=` to distinguish between literal values +異なるリテラル値を区別するには、`===` / `==` / `!==` / `!=` が利用できます。 ```ts type TriState = 'yes' | 'no' | 'unknown'; @@ -115,9 +115,7 @@ function logOutState(state:TriState) { } ``` -This even works when you have literal types in a union. You can check the value of a shared property name to discriminate the union e.g. - -あなたがユニオン型にリテラル型を持っているとき、それらをチェックして区別することができます。 +ユニオン型の中にリテラル型がある場合にも同じ方法が使えます。次のように共通するプロパティの値をチェックすることで、異なるユニオン型を区別できます。 ```ts type Foo = { From 26ea52f0a0ac2a11fd2e7013e0a4f396e5e6e55f Mon Sep 17 00:00:00 2001 From: TAKAHASHI Shuuji Date: Sat, 21 Dec 2019 15:03:19 +0900 Subject: [PATCH 11/35] Translate docs/types/typeGuard.md. --- docs/types/typeGuard.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/types/typeGuard.md b/docs/types/typeGuard.md index 16eff0bae..290460e7e 100644 --- a/docs/types/typeGuard.md +++ b/docs/types/typeGuard.md @@ -139,9 +139,9 @@ function doStuff(arg: Foo | Bar) { } ``` -### null and undefined with `strictNullChecks` +### `strictNullChecks`を使用したnullとundefinedのチェック -TypeScript is smart enough to rule out both `null` and `undefined` with a `== null` / `!= null` check. For example: +TypeScriptは十分賢いので、次のように`== null` / `!= null`チェックをすることで`null`と`undefined`の両方を排除できます。 ```ts function foo(a?: number | null) { @@ -193,11 +193,11 @@ doStuff({ foo: 123, common: '123' }); doStuff({ bar: 123, common: '123' }); ``` -### Type Guards and callbacks +### Type Guardsとコールバック TypeScript doesn't assume type guards remain active in callbacks as making this assumption is dangerous. e.g. -```js +```ts // Example Setup declare var foo:{bar?: {baz: string}}; function immediate(callback: ()=>void) { From 0bda6de3f204c36d449fda277bd88b9d82137cf5 Mon Sep 17 00:00:00 2001 From: TAKAHASHI Shuuji Date: Sat, 21 Dec 2019 15:03:31 +0900 Subject: [PATCH 12/35] Update docs/types/literal-types.md. --- docs/types/literal-types.md | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/docs/types/literal-types.md b/docs/types/literal-types.md index 4827b80c2..3f8b1dbf9 100644 --- a/docs/types/literal-types.md +++ b/docs/types/literal-types.md @@ -9,7 +9,7 @@ let foo: 'Hello'; ``` -ここでは`foo`という名前の変数を作成しました。それに代入されるリテラル値は`Hello`のみを許可します。これは以下のとおりです: +ここでは`foo`という名前の変数を作成しました。それに代入されるリテラル値は`'Hello'`のみを許可します。これは以下のとおりです: ```ts let foo: 'Hello'; @@ -20,7 +20,7 @@ foo = 'Bar'; // Error: "Bar" is not assignable to type "Hello" ```ts type CardinalDirection = - "North" + | "North" | "East" | "South" | "West"; @@ -62,6 +62,19 @@ const test = { iTakeFoo(test.someProp); // Okay! ``` +or use a type annotation that helps TypeScript infer the correct thing at the point of declaration: + +``` +function iTakeFoo(foo: 'foo') { } +type Test = { + someProp: 'foo', +} +const test: Test = { // Annotate - inferred someProp is always === 'foo' + someProp: 'foo' +}; +iTakeFoo(test.someProp); // Okay! +``` + ### ユースケース 文字列型の有効な使用例は次のとおりです。 From 75424976738e678aa9f81ff7d3c9a564f9628634 Mon Sep 17 00:00:00 2001 From: TAKAHASHI Shuuji Date: Sat, 21 Dec 2019 15:28:45 +0900 Subject: [PATCH 13/35] Translate docs/types/literal-types.md. --- docs/types/literal-types.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/types/literal-types.md b/docs/types/literal-types.md index 3f8b1dbf9..06d45bda2 100644 --- a/docs/types/literal-types.md +++ b/docs/types/literal-types.md @@ -44,7 +44,7 @@ type Bools = true | false; ### 推論 かなり一般的に`Type string is not assignable to type "foo"`というエラーを受け取ります。次の例はこれを示しています。 -```js +```ts function iTakeFoo(foo: 'foo') { } const test = { someProp: 'foo' @@ -54,7 +54,7 @@ iTakeFoo(test.someProp); // Error: Argument of type string is not assignable to これは、`test`が`{someProp: string} `型であると推定されるためです。この問題を解決するには、シンプルな型アサーションを使用して、TypeScriptに以下のようにリテラルを推測させます。 -```js +```ts function iTakeFoo(foo: 'foo') { } const test = { someProp: 'foo' as 'foo' @@ -62,9 +62,9 @@ const test = { iTakeFoo(test.someProp); // Okay! ``` -or use a type annotation that helps TypeScript infer the correct thing at the point of declaration: +あるいは、型アノテーションを使うことで、宣言した時点でTypeScriptが正しい型を推論するのを助けることができます。 -``` +```ts function iTakeFoo(foo: 'foo') { } type Test = { someProp: 'foo', From 003a0ef6398c2335ab3eafcc3834d89e929dbf35 Mon Sep 17 00:00:00 2001 From: TAKAHASHI Shuuji Date: Sat, 21 Dec 2019 15:29:13 +0900 Subject: [PATCH 14/35] Update docs/types/readonly.md. --- docs/types/readonly.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/types/readonly.md b/docs/types/readonly.md index 6f0c8b171..9af8b9a13 100644 --- a/docs/types/readonly.md +++ b/docs/types/readonly.md @@ -158,7 +158,7 @@ var bar: { } ``` -2: +説明のためのサンプル2: ```ts let foo: { From b2cb56137e1cbf3a215e21fbe6d369411f79f8fa Mon Sep 17 00:00:00 2001 From: TAKAHASHI Shuuji Date: Sat, 21 Dec 2019 16:52:06 +0900 Subject: [PATCH 15/35] Update docs/types/generics.md. --- docs/types/generics.md | 49 ++++++++++++++++++++++-------------------- 1 file changed, 26 insertions(+), 23 deletions(-) diff --git a/docs/types/generics.md b/docs/types/generics.md index 314863fde..da3813d5c 100644 --- a/docs/types/generics.md +++ b/docs/types/generics.md @@ -14,8 +14,8 @@ ```ts class Queue { private data = []; - push = (item) => this.data.push(item); - pop = () => this.data.shift(); + push(item) { this.data.push(item); } + pop() { return this.data.shift(); } } ``` @@ -24,8 +24,8 @@ class Queue { ```ts class Queue { private data = []; - push = (item) => this.data.push(item); - pop = () => this.data.shift(); + push(item) { this.data.push(item); } + pop() { return this.data.shift(); } } const queue = new Queue(); @@ -40,10 +40,9 @@ console.log(queue.pop().toPrecision(1)); // RUNTIME ERROR 1つの解決策(実際にはジェネリックをサポートしていない言語での唯一の解決策)は、これらの制約のために特別なクラスを作成することです。例えば素早くダーティに数値型のキューを作ります: ```ts -class QueueNumber { - private data = []; - push = (item: number) => this.data.push(item); - pop = (): number => this.data.shift(); +class QueueNumber extends Queue { + push(item: number) { super.push(item); } + pop(): number { return this.data.shift(); } } const queue = new QueueNumber(); @@ -59,8 +58,8 @@ queue.push("1"); // ERROR : cannot push a string. Only numbers allowed /** A class definition with a generic parameter */ class Queue { private data = []; - push = (item: T) => this.data.push(item); - pop = (): T => this.data.shift(); + push(item: T) { this.data.push(item); } + pop(): T | undefined { return this.data.shift(); } } /** Again sample usage */ @@ -108,20 +107,8 @@ class Utility { } ``` -> ヒント:必要に応じてジェネリックパラメータを呼び出すことができます。単純なジェネリックを使うときは `T`、`U`、`V`を使うのが普通です。複数のジェネリック引数がある場合は、意味のある名前を使用してください。例えば`TKey`と`TValue`です(一般に`T`を接頭辞として使用する規約は、他の言語(例えばC++)ではテンプレートと呼ばれることもあります)。 - -## 役に立たずのジェネリック - -私は人々が興味本位でジェネリックを使用しているのを見ました。考えるべき質問は、何を表現しようとしているのか?です。あなたが簡単にそれに答えることができない場合は、役に立たないジェネリックかもしれません。例えば次の関数です: +> ヒント:必要に応じてジェネリックパラメータを呼び出すことができます。単純なジェネリックを使うときは `T`、`U`、`V`を使うのが普通です。複数のジェネリック引数がある場合は、意味のある名前を使用してください。例えば`TKey`と`TValue`です(一般に`T`を接頭辞として使用する規約は、他の言語(例えばC++)では*テンプレート*と呼ばれることもあります)。 -```ts -declare function foo(arg: T): void; -``` -ここでは、ジェネリック`T`は、一箇所の引数の位置でのみ使用されるので完全に不要です。これは次のコードと同じです: - -```ts -declare function foo(arg: any): void; -``` ### デザインパターン:便利なジェネリック @@ -173,3 +160,19 @@ function loadUsers() { ``` 戻り値としての`Promise`は、`Promise`よりも断然優れています。 + +Another example is where a generic is only used as an argument: + +```ts +declare function send(arg: T): void; +``` + +Here the generic `T` can be used to annote the type that you want the argument to match e.g. + +```ts +send({ + x:123, + // Also you get autocomplete +}); // Will TSError if `x:123` does not match the structure expected for Something + +``` From 13c3f766e6c5aeb750ae5d51d16c9deb9348ca59 Mon Sep 17 00:00:00 2001 From: TAKAHASHI Shuuji Date: Sat, 21 Dec 2019 16:55:07 +0900 Subject: [PATCH 16/35] Translate docs/types/generics.md. --- docs/types/generics.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/types/generics.md b/docs/types/generics.md index da3813d5c..8678643b1 100644 --- a/docs/types/generics.md +++ b/docs/types/generics.md @@ -161,13 +161,13 @@ function loadUsers() { 戻り値としての`Promise`は、`Promise`よりも断然優れています。 -Another example is where a generic is only used as an argument: +次の例では、ジェネリックが引数のみに使用されています。 ```ts declare function send(arg: T): void; ``` -Here the generic `T` can be used to annote the type that you want the argument to match e.g. +このようにすると、次のように、引数にマッチさせたい型をアノテートするのにジェネリック`T`を利用できます。 ```ts send({ From e3fdfe83084afc24b26dca1cf445fb0b8dbb9db1 Mon Sep 17 00:00:00 2001 From: TAKAHASHI Shuuji Date: Sat, 21 Dec 2019 17:07:17 +0900 Subject: [PATCH 17/35] Fix a comma in the type, which should not be translated. --- docs/types/type-inference.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/types/type-inference.md b/docs/types/type-inference.md index fcb200d0c..3d1d80ed2 100644 --- a/docs/types/type-inference.md +++ b/docs/types/type-inference.md @@ -168,5 +168,5 @@ function addOne(a) { ## `noImplicitAny` フラグ `noImplicitAny`は、変数の型を推測できない場合(したがって、暗黙の`any`型としてしか持つことができない場合)、エラーを発生させるようにコンパイラに指示します。それによって、次のことが可能です。 -* そうしたい場合は、明示的に`: any`型の注釈を加えることで`any`型にしたい +* そうしたい場合は、明示的に`:any`型の注釈を加えることで`any`型にしたい * 正しいアノテーションを追加することによってコンパイラを助ける From 2ddfac0c2c61fc605955b0dcf3d8c5a237f1e5ce Mon Sep 17 00:00:00 2001 From: TAKAHASHI Shuuji Date: Sat, 21 Dec 2019 17:48:34 +0900 Subject: [PATCH 18/35] Update docs/types/never.md. --- docs/types/never.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/types/never.md b/docs/types/never.md index 183803bcd..013af2f65 100644 --- a/docs/types/never.md +++ b/docs/types/never.md @@ -41,7 +41,7 @@ function foo(x: string | number): boolean { // Without a never type we would error : // - Not all code paths return a value (strict null checks) // - Or Unreachable code detected - // But because typescript understands that `fail` function returns `never` + // But because TypeScript understands that `fail` function returns `never` // It can allow you to call it as you might be using it for runtime safety / exhaustive checks. return fail("Unexhaustive!"); } From 166352c80a892a06e82281f7ecd2106102d4571f Mon Sep 17 00:00:00 2001 From: TAKAHASHI Shuuji Date: Sat, 21 Dec 2019 17:57:47 +0900 Subject: [PATCH 19/35] Update docs/types/discriminated-unions.md. --- docs/types/discriminated-unions.md | 83 +++++++++++++++++++++++++++++- 1 file changed, 82 insertions(+), 1 deletion(-) diff --git a/docs/types/discriminated-unions.md b/docs/types/discriminated-unions.md index 5a6313d13..21e82493b 100644 --- a/docs/types/discriminated-unions.md +++ b/docs/types/discriminated-unions.md @@ -143,6 +143,87 @@ function area(s: Shape) { } ``` +### Throw in exhaustive checks +You can write a function that takes a `never` (and therefore can only be called with a variable that is inferred as `never`) and then throws an error if its body ever executes: + +```ts +function assertNever(x:never): never { + throw new Error('Unexpected value. Should have been never.'); +} +``` + +Example use with the area function: + +```ts +interface Square { + kind: "square"; + size: number; +} +interface Rectangle { + kind: "rectangle"; + width: number; + height: number; +} +type Shape = Square | Rectangle; + +function area(s: Shape) { + switch (s.kind) { + case "square": return s.size * s.size; + case "rectangle": return s.width * s.height; + // If a new case is added at compile time you will get a compile error + // If a new value appears at runtime you will get a runtime error + default: return assertNever(s); + } +} +``` + +### Retrospective Versioning +Say you have a data structure of the form: + +```ts +type DTO = { + name: string +} +``` +And after you have a bunch of `DTO`s you realize that `name` was a poor choice. You can add versioning retrospectively by creating a new *union* with *literal number* (or string if you want) of DTO. Mark the version 0 as `undefined` and if you have *strictNullChecks* enabled it will just work out: + +```ts +type DTO = +| { + version: undefined, // version 0 + name: string, + } +| { + version: 1, + firstName: string, + lastName: string, +} +// Even later +| { + version: 2, + firstName: string, + middleName: string, + lastName: string, +} +// So on +``` + + Example usage of such a DTO: + +```ts +function printDTO(dto:DTO) { + if (dto.version == null) { + console.log(dto.name); + } else if (dto.version == 1) { + console.log(dto.firstName,dto.lastName); + } else if (dto.version == 2) { + console.log(dto.firstName, dto.middleName, dto.lastName); + } else { + const _exhaustiveCheck: never = dto; + } +} +``` + ### Redux これを活用しているポピュラーなライブラリはreduxです。 @@ -189,7 +270,7 @@ let store = createStore(counter) // You can use subscribe() to update the UI in response to state changes. // Normally you'd use a view binding library (e.g. React Redux) rather than subscribe() directly. -// However it can also be handy to persist the current state in the localStorage. +// However, it can also be handy to persist the current state in the localStorage. store.subscribe(() => console.log(store.getState()) From 54a9482ab1ae8bb0d06f01ae1f39c3b6586440fe Mon Sep 17 00:00:00 2001 From: TAKAHASHI Shuuji Date: Sat, 21 Dec 2019 21:38:44 +0900 Subject: [PATCH 20/35] Translate docs/types/discriminated-unions.md. --- docs/types/discriminated-unions.md | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/docs/types/discriminated-unions.md b/docs/types/discriminated-unions.md index 21e82493b..a9c1b6ae0 100644 --- a/docs/types/discriminated-unions.md +++ b/docs/types/discriminated-unions.md @@ -143,8 +143,9 @@ function area(s: Shape) { } ``` -### Throw in exhaustive checks -You can write a function that takes a `never` (and therefore can only be called with a variable that is inferred as `never`) and then throws an error if its body ever executes: +### 網羅チェックの中で例外を投げる + +引数として`never`を取る関数を書くことができます(したがって、この関数は`never`として推論された変数で呼ばれた場合にのみ呼ばれます)。そして、次のように、関数の本体が実行された場合に例外を投げるように書きます。 ```ts function assertNever(x:never): never { @@ -152,7 +153,7 @@ function assertNever(x:never): never { } ``` -Example use with the area function: +以下に、`area`関数とともに使用する例を示します。 ```ts interface Square { @@ -178,14 +179,16 @@ function area(s: Shape) { ``` ### Retrospective Versioning -Say you have a data structure of the form: + +次のような形のデータ構造があるとします。 ```ts type DTO = { name: string } ``` -And after you have a bunch of `DTO`s you realize that `name` was a poor choice. You can add versioning retrospectively by creating a new *union* with *literal number* (or string if you want) of DTO. Mark the version 0 as `undefined` and if you have *strictNullChecks* enabled it will just work out: + +そして、`DTO`をさまざまな場所で使用した後に、`name`という名前は良くない選択だったことに気が付いたとします。このような場合には、*リテラルの数値*(または望むなら文字列)を追加したDTOの新しい*ユニオン型*を定義することで、後から型にバージョニングを追加することができます。*strictNullChecks*を有効にしていれば、バージョン0を`undefined`とマークするだけで、そのバージョンの型が使われているかどうかのチェックを自動的に行えます。 ```ts type DTO = @@ -208,7 +211,7 @@ type DTO = // So on ``` - Example usage of such a DTO: +このように定義したDTOは、次のように利用します。 ```ts function printDTO(dto:DTO) { @@ -226,7 +229,7 @@ function printDTO(dto:DTO) { ### Redux -これを活用しているポピュラーなライブラリはreduxです。 +ユニオン判別を活用しているポピュラーなライブラリはreduxです。 ここに、TypeScript型アノテーションを追加した [*gist of redux*](https://github.com/reactjs/redux#the-gist) があります: From cf66d5058bdec4d2c8213a11a5f8776699b0fb03 Mon Sep 17 00:00:00 2001 From: TAKAHASHI Shuuji Date: Sat, 21 Dec 2019 22:38:03 +0900 Subject: [PATCH 21/35] Remove a space. --- docs/types/index-signatures.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/types/index-signatures.md b/docs/types/index-signatures.md index 696d94ce5..ef503a837 100644 --- a/docs/types/index-signatures.md +++ b/docs/types/index-signatures.md @@ -212,7 +212,7 @@ interface ArrStr { > インデックスシグネチャを追加する際のAPIの考慮事項 -JSコミュニティでは、通常、文字列インデクサを乱用するAPIをよく見かけるでしょう。例えばJSライブラリ におけるCSSの共通パターンです: +JSコミュニティでは、通常、文字列インデクサを乱用するAPIをよく見かけるでしょう。例えばJSライブラリにおけるCSSの共通パターンです: ```ts interface NestedCSS { From e177610092aef44523413eed873f16db4076ff66 Mon Sep 17 00:00:00 2001 From: TAKAHASHI Shuuji Date: Sat, 21 Dec 2019 22:59:41 +0900 Subject: [PATCH 22/35] Update docs/types/moving-types.md. --- docs/types/moving-types.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/types/moving-types.md b/docs/types/moving-types.md index e86430611..c7489bd31 100644 --- a/docs/types/moving-types.md +++ b/docs/types/moving-types.md @@ -53,7 +53,7 @@ class Foo { declare let _foo: Foo; // Same as before -let bar: typeof _foo.foo; +let bar: typeof _foo.foo; // `bar` has type `number` ``` ## マジック文字列の種類を取得する @@ -88,7 +88,7 @@ type Colors = keyof typeof colors; let color: Colors; // same as let color: "red" | "blue" color = 'red'; // okay color = 'blue'; // okay -color = 'anythingElse'; // Error +color = 'anythingElse'; // Error: Type '"anythingElse"' is not assignable to type '"red" | "blue"' ``` 上記の例のように、文字列列挙型+定数のようなものを簡単に作成することができます。 From 2f7ff24b5e213067fd2db3080109c6e96182e30d Mon Sep 17 00:00:00 2001 From: TAKAHASHI Shuuji Date: Sat, 21 Dec 2019 23:07:46 +0900 Subject: [PATCH 23/35] Fix the language name of the code block. --- docs/types/exceptions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/types/exceptions.md b/docs/types/exceptions.md index 96a5bea3d..12bea9564 100644 --- a/docs/types/exceptions.md +++ b/docs/types/exceptions.md @@ -78,7 +78,7 @@ catch(e) { `Error`オブジェクトを渡すことは大丈夫です。これは、Node.jsのコールバックスタイルコードでは、最初の引数をエラーオブジェクトとしてコールバックを受け取ります。 -```js +```ts function myFunction (callback: (e?: Error)) { doSomethingAsync(function () { if (somethingWrong) { From 2195b46f67979c17898211440a132c61e72b355f Mon Sep 17 00:00:00 2001 From: TAKAHASHI Shuuji Date: Sat, 21 Dec 2019 23:26:15 +0900 Subject: [PATCH 24/35] Refine a translation. --- docs/types/mixins.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/types/mixins.md b/docs/types/mixins.md index 5154297ab..b236140b0 100644 --- a/docs/types/mixins.md +++ b/docs/types/mixins.md @@ -9,7 +9,7 @@ class User extends Tagged, Timestamped { // ERROR : no multiple inheritance 再使用可能なコンポーネントからクラスを構築する別の方法は、mixinと呼ばれるより単純な部分クラスを組み合わせてそれらを構築することです。 -そのアイデアは、機能を得るためにクラスAを拡張する*クラスAの代わりに単純です。*関数BはクラスA を取り、この追加された機能を持つ新しいクラスを返します。関数`B`はミックスインです。 +アイデアはシンプルです。クラスBの機能を得るために*クラスBを拡張するクラスAを*定義するのではなく、その代わりに*クラスAを取る関数B*を定義して、機能を追加した新しいクラスを返すようにするのです。関数`B`はミックスインです。 > [mixinは] > From 0ac2214a61d373ae00df81b4a14031cae1f7430f Mon Sep 17 00:00:00 2001 From: TAKAHASHI Shuuji Date: Sat, 21 Dec 2019 23:44:35 +0900 Subject: [PATCH 25/35] Update docs/jsx/react.md. --- docs/jsx/react.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/jsx/react.md b/docs/jsx/react.md index b1c459f96..daad7fae7 100644 --- a/docs/jsx/react.md +++ b/docs/jsx/react.md @@ -34,22 +34,22 @@ declare module JSX { } ``` -### ステートレスな関数コンポーネント(Stateless Functional Components) +### 関数コンポーネント(Functional Components) -あなたは単に`React.SFC`インターフェースを使ってステートレスなコンポーネントを定義することができます。 +あなたは単に`React.FunctionComponent`インターフェースを使ってステートレスなコンポーネントを定義することができます。 ```ts type Props = { foo: string; } -const MyComponent: React.SFC = (props) => { +const MyComponent: React.FunctionComponent = (props) => { return {props.foo} } ``` -### ステートフルなコンポーネント(Stateful Components) +### クラスコンポーネント(Class Components) コンポーネントは、コンポーネントの`props`プロパティに基づいて型チェックされます。これは、JSXがどのように変換されるかによってモデル化されています。例えば属性がコンポーネントの`props`になるようにモデル化されています。 @@ -181,7 +181,7 @@ class FocusingInput extends React.Component<{ value: string, onChange: (value: s this.input = input} value={this.props.value} - onChange={(e) => { this.props.onChange(this.ctrls.input.value) } } + onChange={(e) => { this.props.onChange(e.target.value) } } /> ); } From 9a999f8a02d522c00c3f3236fb1f2f92fcae52a5 Mon Sep 17 00:00:00 2001 From: TAKAHASHI Shuuji Date: Sun, 22 Dec 2019 16:42:53 +0900 Subject: [PATCH 26/35] Update and fix docs/errors/common-errors.md. --- docs/errors/common-errors.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/errors/common-errors.md b/docs/errors/common-errors.md index 49fc03ba3..ad1e0546d 100644 --- a/docs/errors/common-errors.md +++ b/docs/errors/common-errors.md @@ -3,7 +3,9 @@ ## TS2304 サンプル: -> `Cannot find name ga` `Cannot find name $` `Cannot find module jquery` +> `Cannot find name ga` +> `Cannot find name $` +> `Cannot find module jquery` おそらく第三者のライブラリ(Googleアナリティクスなど)を使用しており、宣言していません。TypeScriptは、*スペルミス*や宣言しないで変数を使用すると、あなたを助けようとします。あなたは外部ライブラリを取り込んでいるので実行時に利用可能なものに明示する必要があります([修正方法](../types/ambient/d.ts.md))。 @@ -15,7 +17,7 @@ ## TS1148 サンプル: -> `'Cannot compile modules unless the '--module' flag is provided` +> `Cannot compile modules unless the '--module' flag is provided` [モジュール](../project/modules.md)のセクションをチェックしてください。 From 21be7e1ab3a44bd77c8f608a34490ff8d7337c92 Mon Sep 17 00:00:00 2001 From: TAKAHASHI Shuuji Date: Sun, 22 Dec 2019 17:26:11 +0900 Subject: [PATCH 27/35] Update and fix docs/testing/jest.md. --- docs/testing/jest.md | 36 +++++++++++++++--------------------- 1 file changed, 15 insertions(+), 21 deletions(-) diff --git a/docs/testing/jest.md b/docs/testing/jest.md index 9336db000..266dddb68 100644 --- a/docs/testing/jest.md +++ b/docs/testing/jest.md @@ -16,9 +16,9 @@ npm i jest @types/jest ts-jest -D 説明: -* `jest`フレームワークをインストールします(`jest`) -* `jest`の型をインストールしてください(`@types/jest`) -* Jest(`ts-jest`)用のTypeScriptプリプロセッサをインストールしてください。これにより、Jestはその場でTypeScriptをトランスパイルすることができ、source-mapをサポートします +* `jest`フレームワーク(`jest`)をインストールします +* `jest`の型(`@types/jest`)をインストールします +* Jest用のTypeScriptプリプロセッサ(`ts-jest`)をインストールします。これにより、Jestはその場でTypeScriptをトランスパイルすることができ、source-mapをサポートします * これらのすべてを、あなたのdevの依存関係に保存してください(テストはほとんど常にnpmのdev-dependencyです) ## ステップ2:Jestを設定する @@ -30,27 +30,21 @@ module.exports = { "roots": [ "/src" ], + "testMatch": [ + "**/__tests__/**/*.+(ts|tsx|js)", + "**/?(*.)+(spec|test).+(ts|tsx|js)" + ], "transform": { - "^.+\\.tsx?$": "ts-jest" + "^.+\\.(ts|tsx)$": "ts-jest" }, - "testRegex": "(/__tests__/.*|(\\.|/)(test|spec))\\.tsx?$", - "moduleFileExtensions": [ - "ts", - "tsx", - "js", - "jsx", - "json", - "node" - ], } ``` 説明: * *すべての*TypeScriptファイルをプロジェクトの`src`フォルダに入れることを常にお勧めします。これが前提とし、`roots`オプションを使用してこれを指定します。 +* `testMatch`設定は、ts/tsx/jsフォーマットで書かれた.test/.specファイルを発見するためのglobのパターンマッチャーです。 * `transform`設定は、`jest`にts/tsxファイルに対して`ts-jest`を使うように指示します。 -* `testRegex`はJestに`__tests__`フォルダ内のテストを検索するよう指示します。また`(.test|.spec).(ts|tsx)`拡張子を使用する任意のファイルを検索します。 例えば、`asdf.test.tsx`など。 -* `moduleFileExtensions`はjestに私達のファイル拡張子を認識させます。これは`ts`/`tsx`をデフォルト(`js|jsx|json|node`)に追加するときに必要です。 ## 手順3:テストを実行する @@ -86,7 +80,7 @@ export const sum * 単純な`foo.test.ts`: ```js -import { sum } from '../'; +import { sum } from '../foo'; test('basic', () => { expect(sum()).toBe(0); @@ -107,7 +101,7 @@ test('basic again', () => { Jestには、async/awaitサポートが組み込まれています。例えば: ```js -test('basic',async () => { +test('basic', async () => { expect(sum()).toBe(0); }); @@ -131,15 +125,15 @@ module.exports = { // Setup Enzyme "snapshotSerializers": ["enzyme-to-json/serializer"], - "setupTestFrameworkScriptFile": "/src/setupEnzyme.ts", + "setupFilesAfterEnv": ["/src/setupEnzyme.ts"], } ``` -3. `src / setupEnzyme.ts`ファイルを作成します。 +3. `src/setupEnzyme.ts`ファイルを作成します。 ```js import { configure } from 'enzyme'; -import * as EnzymeAdapter from 'enzyme-adapter-react-16'; +import EnzymeAdapter from 'enzyme-adapter-react-16'; configure({ adapter: new EnzymeAdapter() }); ``` @@ -197,7 +191,7 @@ test('CheckboxWithLabel changes the text after click', () => { expect(checkbox.text()).toEqual('On'); // Snapshot demo - expect(shallow).toMatchSnapshot(); + expect(checkbox).toMatchSnapshot(); }); ``` From fbc30207bf2ce1e6eff6a12f40f1ad573ae45f6d Mon Sep 17 00:00:00 2001 From: TAKAHASHI Shuuji Date: Sun, 22 Dec 2019 18:08:43 +0900 Subject: [PATCH 28/35] Update docs/testing/cypress.md. --- docs/testing/cypress.md | 138 +++++++++++++++++++++++++++++----------- 1 file changed, 101 insertions(+), 37 deletions(-) diff --git a/docs/testing/cypress.md b/docs/testing/cypress.md index a434c717b..d824f8b0f 100644 --- a/docs/testing/cypress.md +++ b/docs/testing/cypress.md @@ -10,6 +10,8 @@ Cypressは素晴らしいE2Eテストツールです。これを考慮する大 ## インストール +> You can skip this section by just cloning [the template github repo 🌹](https://github.com/basarat/cypress-ts) + > このインストールプロセスで提供される手順は、あなたの組織のボイラープレートとして使用できる素敵なe2eフォルダを提供します。このe2eフォルダをCypressでテストしたい既存のプロジェクトに貼り付けてコピーすることができます e2eディレクトリを作成し、cypressとその依存関係をTypeScriptのトランスパイルのためにインストールします。 @@ -165,65 +167,94 @@ const page = new LoginPage(); page.visit(); page.username.type('john'); + ``` -## ヒント:暗黙のアサーション -Cypresssコマンドが失敗したときには、(他の多くのフレームワークでは`null`のようなものではなく)素晴らしいエラーが発生するので、すばやく失敗し、テストが失敗したときを正確に知ることができます。 +## ヒント:明示的なアサーション +Cypressには、ウェブ用のほんのいくつかのアサーションヘルプが付属しています。例えば、chai-jquery https://docs.cypress.io/guides/references/assertions.html#Chai-jQuery です。 それらを使うには、`.should`コマンドを使用して、chainerに文字列として渡します: ``` -cy.get('#foo') -// If there is no element with id #foo cypress will wait for 4 seconds automatically -// If still not found you get an error here ^ -// \/ This will not trigger till an element #foo is found - .should('have.text', 'something') +cy.get('#foo') + .should('have.text', 'something') ``` +> You get intellisense for `should` chainers as cypress ships with correct TypeScript definitions 👍🏻 -## ヒント:明示的なアサーション -Cypressには、ウェブ用のほんのいくつかのアサーションヘルプが付属しています。例えば、chai-jquery https://docs.cypress.io/guides/references/assertions.html#Chai-jQuery です。 それらを使うには、`.should`コマンドを使用して、chainerに文字列として渡します: +The complete list of chainers is available here : https://docs.cypress.io/guides/references/assertions.html + +If you want something complex you can even use `should(callback)` and e.g. ``` -cy.get('#foo') - .should('have.text', 'something') +cy.get('div') + .should(($div) => { + expect($div).to.have.length(1); + expect($div[0].className).to.contain('heading'); + }) +// This is just an example. Normally you would `.should('have.class', 'heading') ``` +> TIP: cypress with do automatic retries on the callback as well, so they are just as flake free as standard string chainers. + ## ヒント:コマンドとチェーン cypressチェーン内のすべての関数呼び出しは`command`です。`should`コマンドはアサーションです。チェーンとアクションの別々の*カテゴリ*を別々に開始することは慣習になっています: ```ts -// Don't do this -cy.get(/**something*/) +// Don't do this +cy.get(/**something*/) .should(/**something*/) .click() .should(/**something*/) - .get(/**something else*/) + .get(/**something else*/) .should(/**something*/) -// Prefer seperating the two gets -cy.get(/**something*/) +// Prefer separating the two gets +cy.get(/**something*/) .should(/**something*/) .click() .should(/**something*/) -cy.get(/**something else*/) +cy.get(/**something else*/) .should(/**something*/) ``` 他の何かのライブラリは、同時にこのコードを評価し、実行します。それらのライブラリは、単一のチェーンが必要になります。それはセレクタやアサーションが混在してデバッグを行うのが難しくなります。 -サイプレスコマンドは、本質的に、コマンドを後で実行するためのCypressランタイムへの*宣言*です。端的な言葉:Cypressはより簡単にします +Cypressのコマンドは、本質的に、コマンドを後で実行するためのCypressランタイムへの*宣言*です。端的な言葉:Cypressはより簡単にします ## ヒント: より容易なクエリのために`contains`を使う 下記に例を示します: ```ts -cy.get('#foo') +cy.get('#foo') // Once #foo is found the following: - .contains('Submit') + .contains('Submit') + .click() // ^ will continue to search for something that has text `Submit` and fail if it times out. + // ^ After it is found trigger a click on the HTML Node that contained the text `Submit`. +``` + +## ヒント:スマートディレイとリトライ +Cypressはたくさんの非同期のものに対して、自動的に待ち(そしてリトライし)ます。 +``` +// If there is no request against the `foo` alias cypress will wait for 4 seconds automatically +cy.wait('@foo') +// If there is no element with id #foo cypress will wait for 4 seconds automatically and keep retrying +cy.get('#foo') +``` +これにより、テストコードフローに常に任意のタイムアウトのロジックを追加する必要がなくなります。 + +## Tip: Implicit assertion +Cypress has a concept of implicit assertion. These kick in if a future command is erroring because of a previous command. E.g. the following will error at `contains` (after automatic retries of course) as nothing found can get `click`ed: + +```ts +cy.get('#foo') + // Once #foo is found the following: + .contains('Submit') .click() - // ^ will trigger a click on the HTML Node that contained the text `Submit`. + // ^ Error: #foo does not have anything that `contains` `'Submit'` ``` +In traditional frameworks you would get a horrible error like `click` doesn't exist on `null`. In Cypress you get a nice error `#foo` does not contain `Submit`. This error is a form of an implicit assertion. + ## ヒント: HTTPリクエストを待つ アプリケーションが作るXHRに必要なすべてのタイムアウトが原因となり、多くのテストが脆くなりました。`cy.server`は次のことを簡単にします。 * バックエンド呼び出しのエイリアスを作成する @@ -240,7 +271,7 @@ cy.server() cy.visit('/') // wait for the call -cy.wait('@load') +cy.wait('@load') // Now the data is loaded ``` @@ -249,7 +280,21 @@ cy.wait('@load') `route`を使ってリクエストのレスポンスを簡単にモックすることもできます: ```ts cy.server() - .route('POST', 'https://example.com/api/application/load', /* Example payload response */{success:true}) + .route('POST', 'https://example.com/api/application/load', /* Example payload response */{success:true}); +``` + +### Tip: Asserting an Http request response +You can assert requests without mocking using `route` `onRequest` / `onResponse` e.g. + +```ts +cy.route({ + method: 'POST', + url: 'https://example.com/api/application/load', + onRequest: (xhr) => { + // Example assertion + expect(xhr.request.body.data).to.deep.equal({success:true}); + } +}) ``` ## ヒント:時間をモックする @@ -271,23 +316,13 @@ cy.tick(waitMilliseconds); cy.get('#logoutNotification').should('be.visible'); ``` -## ヒント:スマートディレイとリトライ -Cypressはたくさんの非同期のものに対して、自動的に待ち(そしてリトライし)ます。 -``` -// If there is no request against the `foo` alias cypress will wait for 4 seconds automatically -cy.wait('@foo') -// If there is no element with id #foo cypress will wait for 4 seconds automatically -cy.get('#foo') -``` -これにより、テストコードフローに常に任意のタイムアウトのロジックを追加する必要がなくなります。 - ## ヒント: アプリケーションコードのユニットテスト あなたはCypressを使ってアプリケーションコードを分離してユニットテストを行うことも可能です。 ```ts -import { once } from '../../../src/app/utils'; +import { once } from '../../../src/app/utils'; -// Later +// Later it('should only call function once', () => { let called = 0; const callMe = once(()=>called++); @@ -304,7 +339,10 @@ it('should only call function once', () => { ```ts import { navigate } from 'takeme'; -export function foo() { navigate('/foo'); } + +export function foo() { + navigate('/foo'); +} ``` * 下記を`some.spec.ts`で行います @@ -324,6 +362,29 @@ describe('should work', () => { }); ``` +## Tip: Command - execution separation +When you invoke a cypress command (or assertion) e.g. `cy.get('#something')`, the function immediately returns without actually carrying out the action. What it does do, is informs the cypress test runner that you will need to carry out (execute) an action (in this case a `get`) at some point. + +You are basically building a command list that the runner will then go ahead and execute. You can verify this command - execution separation with a simple test, observe that you will see the `start / between / end` `console.log` statements execute immediately before the runner starts *executing* the commands: + +```ts +/// + +describe('Hello world', () => { + it('demonstrate command - execution separation', () => { + console.log('start'); + cy.visit('http://www.google.com'); + console.log('between'); + cy.get('.gLFyf').type('Hello world'); + console.log('end'); + }); +}); +``` + +This command execution separation has two big benefits: +* The runner can execute the commands in a *flake resistant* manner with automatic retries and implicit assertions. +* Allows you to write asynchronous code in a synchronous fashion without having to do a constant *chaining* which results in difficult to maintain code. + ## TIP: ブレークポイント Cypressテストによって生成された自動スナップショット+コマンドログは、デバッグに最適です。とはいえ、それは、あなたが望むならテストの実行を一時停止できます。 @@ -353,4 +414,7 @@ package.jsonの例: * ウェブサイト:https://www.cypress.io/ * あなたの最初のCypressテストを書く(Cypress IDEの素晴らしいツアー):https://docs.cypress.io/guides/getting-started/writing-your-first-test.html * CI環境を設定する(例えば、そのまま`cypress run`で動く提供されたdockerイメージ):https://docs.cypress.io/guides/guides/continuous-integration.html -* レシピ(説明付きのレシピの一覧です。レシピのソースコードに移動するには見出しをクリックしてください):https://docs.cypress.io/examples/examples/recipes.html +* レシピ(説明付きのレシピの一覧です。レシピのソースコードに移動するには見出しをクリックしてください): https://docs.cypress.io/examples/examples/recipes.html +* Visual Testing: https://docs.cypress.io/guides/tooling/visual-testing.html +* Optionally set a `baseUrl` in cypress.json to [prevent an initial reload that happens after first `visit`.](https://github.com/cypress-io/cypress/issues/2542) +* Code coverage with cypress: [Webcast](https://www.youtube.com/watch?v=C8g5X4vCZJA) From 6545f1874ab5b17bcee054480399b73843134c1d Mon Sep 17 00:00:00 2001 From: TAKAHASHI Shuuji Date: Sun, 22 Dec 2019 19:10:34 +0900 Subject: [PATCH 29/35] Translate docs/testing/cypress.md. --- docs/testing/cypress.md | 50 ++++++++++++++++++++--------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/docs/testing/cypress.md b/docs/testing/cypress.md index d824f8b0f..d75134718 100644 --- a/docs/testing/cypress.md +++ b/docs/testing/cypress.md @@ -10,7 +10,7 @@ Cypressは素晴らしいE2Eテストツールです。これを考慮する大 ## インストール -> You can skip this section by just cloning [the template github repo 🌹](https://github.com/basarat/cypress-ts) +> このセクションで行う設定は、[このテンプレートGitHubリポジトリ 🌹](https://github.com/basarat/cypress-ts)をcloneするだけで完了します。 > このインストールプロセスで提供される手順は、あなたの組織のボイラープレートとして使用できる素敵なe2eフォルダを提供します。このe2eフォルダをCypressでテストしたい既存のプロジェクトに貼り付けてコピーすることができます @@ -78,7 +78,6 @@ module.exports = (on) => { } ``` - 任意に`e2e/package.json`ファイルにいくつかのスクリプトを追加します: ```json @@ -132,7 +131,7 @@ ciモードでCypressテストを実行するには、次のコマンドを使 npm run cypress:run ``` -## ヒント:UIとテストの間でコードを共有する +## ヒント: UIとテストの間でコードを共有する Cypressテストはコンパイル/パックされ、ブラウザで実行されます。プロジェクトコードを自由にテストにインポートしてください。 たとえば、UIセレクタとテストの間でID値を共有して、CSSセレクタが壊れないようにすることができます。 @@ -170,7 +169,7 @@ page.username.type('john'); ``` -## ヒント:明示的なアサーション +## ヒント: 明示的なアサーション Cypressには、ウェブ用のほんのいくつかのアサーションヘルプが付属しています。例えば、chai-jquery https://docs.cypress.io/guides/references/assertions.html#Chai-jQuery です。 それらを使うには、`.should`コマンドを使用して、chainerに文字列として渡します: ``` @@ -189,12 +188,12 @@ cy.get('div') expect($div).to.have.length(1); expect($div[0].className).to.contain('heading'); }) -// This is just an example. Normally you would `.should('have.class', 'heading') +// これは単なる例です。普通は`.should('have.class', 'heading')`のように書きます。 ``` -> TIP: cypress with do automatic retries on the callback as well, so they are just as flake free as standard string chainers. +> ヒント: cypressにはcallbackの呼び出しにも自動リトライ機能があるため、普通の文字列のチェーンと同じように壊れにくいコードを書くことができます。 -## ヒント:コマンドとチェーン +## ヒント: コマンドとチェーン cypressチェーン内のすべての関数呼び出しは`command`です。`should`コマンドはアサーションです。チェーンとアクションの別々の*カテゴリ*を別々に開始することは慣習になっています: ```ts @@ -232,7 +231,7 @@ cy.get('#foo') // ^ After it is found trigger a click on the HTML Node that contained the text `Submit`. ``` -## ヒント:スマートディレイとリトライ +## ヒント: スマートディレイとリトライ Cypressはたくさんの非同期のものに対して、自動的に待ち(そしてリトライし)ます。 ``` // If there is no request against the `foo` alias cypress will wait for 4 seconds automatically @@ -242,8 +241,8 @@ cy.get('#foo') ``` これにより、テストコードフローに常に任意のタイムアウトのロジックを追加する必要がなくなります。 -## Tip: Implicit assertion -Cypress has a concept of implicit assertion. These kick in if a future command is erroring because of a previous command. E.g. the following will error at `contains` (after automatic retries of course) as nothing found can get `click`ed: +## ヒント: 暗黙のアサーション +Cypressには暗黙のアサーションという概念があります。1つ前のコマンドが原因でそれ移行のコマンドでエラーが発生したときに実行されます。These kick in if a future command is erroring because of a previous command. E.g. the following will error at `contains` (after automatic retries of course) as nothing found can get `click`ed: ```ts cy.get('#foo') @@ -253,9 +252,9 @@ cy.get('#foo') // ^ Error: #foo does not have anything that `contains` `'Submit'` ``` -In traditional frameworks you would get a horrible error like `click` doesn't exist on `null`. In Cypress you get a nice error `#foo` does not contain `Submit`. This error is a form of an implicit assertion. +伝統的なフレームワークでは、`null`には`click`がないというような恐ろしいエラーを目にすることでしょう。Cypressの場合、`#foo`には`Submit`が含まれていないという親切なエラーが表示されます。このようなエラーは暗黙のアサーションの1種です。 -## ヒント: HTTPリクエストを待つ +## ヒント: HTTPリクエストを待つ アプリケーションが作るXHRに必要なすべてのタイムアウトが原因となり、多くのテストが脆くなりました。`cy.server`は次のことを簡単にします。 * バックエンド呼び出しのエイリアスを作成する * それらが発生するのを待つ @@ -276,15 +275,16 @@ cy.wait('@load') // Now the data is loaded ``` -## ヒント:HTTPリクエストのレスポンスをモックする +## ヒント: HTTPリクエストのレスポンスをモックする `route`を使ってリクエストのレスポンスを簡単にモックすることもできます: + ```ts cy.server() .route('POST', 'https://example.com/api/application/load', /* Example payload response */{success:true}); ``` -### Tip: Asserting an Http request response -You can assert requests without mocking using `route` `onRequest` / `onResponse` e.g. +### ヒント: HTTPリクエストのレスポンスをアサートする +リクエストのアサートは、モックを作らなくても`route`や`onRequest`/`onResponse`を使うことで実現できます。 ```ts cy.route({ @@ -297,7 +297,7 @@ cy.route({ }) ``` -## ヒント:時間をモックする +## ヒント: 時間をモックする `wait`を使ってある時間テストを一時停止することができます。自動的に"あなたはログアウトされます"という通知画面をテストする例: ```ts @@ -332,7 +332,7 @@ it('should only call function once', () => { }); ``` -## TIP: ユニットテストにおけるモック +## ヒント: ユニットテストにおけるモック もしあなたがアプリケーショのモジュールをユニットテストしていたら、あなたは`cy.stub`を使ってモックを提供することが可能です。例えば、あなたは`navigate`が関数`foo`で呼ばれることを確認できます: * `foo.ts` @@ -362,10 +362,10 @@ describe('should work', () => { }); ``` -## Tip: Command - execution separation -When you invoke a cypress command (or assertion) e.g. `cy.get('#something')`, the function immediately returns without actually carrying out the action. What it does do, is informs the cypress test runner that you will need to carry out (execute) an action (in this case a `get`) at some point. +## ヒント: コマンド - 実行の分離 +たとえば、`cy.get('#something')`のようなCypressのコマンド(またはアサーション)を呼び出したとき、関数は実際には何もアクションを行わずに即座に返ります。実際に関数が行うのは、Cypressのテストランナーに対して、あるアクション(この場合は`get`)をある時点で実行する必要があると伝えることです。 -You are basically building a command list that the runner will then go ahead and execute. You can verify this command - execution separation with a simple test, observe that you will see the `start / between / end` `console.log` statements execute immediately before the runner starts *executing* the commands: +あなたが行うことは、基本的には、ランナーが将来実行することになるコマンドリストを書くことになります。このようにコマンドと実行が分離されていることは、次のようなシンプルなテストを書くことで確かめることができます。このテストを実行すると、ランナーがコマンドを*実行*する前に、`start / between / end`の`console.log`文がすぐに実行されることがわかります。 ```ts /// @@ -381,11 +381,11 @@ describe('Hello world', () => { }); ``` -This command execution separation has two big benefits: -* The runner can execute the commands in a *flake resistant* manner with automatic retries and implicit assertions. -* Allows you to write asynchronous code in a synchronous fashion without having to do a constant *chaining* which results in difficult to maintain code. +このようなコマンドの実行の分離を行うことには、2つの利点があります。 +* ランナーがコマンドを実行するときに、*脆さに耐えられる*やり方で自動リトライや暗黙のアサーションを実行できる。 +* 非同期に書くコードを同期的に書くことができるため、コードのメンテナンスが難しくなってしまう常に*チェーンする*ような書き方をする必要がなくなる。 -## TIP: ブレークポイント +## ヒント: ブレークポイント Cypressテストによって生成された自動スナップショット+コマンドログは、デバッグに最適です。とはいえ、それは、あなたが望むならテストの実行を一時停止できます。 まずChrome Developer Tools(愛情を込めてdev toolsと呼ばれています)をテストランナー(macでは`CMD + ALT + i`/windowsでは`F12`)で開いていることを確認してください。一度dev toolsを開けば、あなたはテストをリランすることができ、dev toolsは開いたままになります。もしdev toolsを開いていれば、あなたは2つの方法でテストを実行できます: @@ -393,7 +393,7 @@ Cypressテストによって生成された自動スナップショット+コマ * アプリケーションコードのブレークポイント: `debugger`文をアプリケーションのコードを使うと、テストランナーは通常のweb開発のように、ちょうどそこで停止します。 * テストコードのブレークポイント: あなたは`.debug()`コマンドを使い、cypressのテスト実行をそこで停止できます。例えば、`.then(() => { debugger })`です。あなたはいくつかのエレメントを得ること(`cy.get('#foo').then(($ /* a reference to the dom element */) => { debugger; })`)や、ネットワーク呼び出し(`cy.request('https://someurl').then((res /* network response */) => { debugger });`)すら可能です。しかし、慣用的な方法は、`cy.get('#foo').debug()`です。そして、テストランナーが`debug`で止まったときに、`get`をコマンドログでクリックすると自動的に`console.log`にあなたが知りたい`.get('#foo')`に関する情報が出力されます(そして、デバッグに必要な他のコマンドでも似たようなものです) -## TIP: サーバーを開始してテストを実行する +## ヒント: サーバーを開始してテストを実行する もしテストの前にローカルサーバを起動したい場合は`start-server-and-test` [https://github.com/bahmutov/start-server-and-test](https://github.com/bahmutov/start-server-and-test) を依存関係に追加できます。それは次の引数を受け取ります。 * サーバーを実行するためのnpmスクリプト * サーバーが起動しているかをチェックするためのエンドポイント From 2a06dfac4c9da81d50532c9881a4cde3b6121167 Mon Sep 17 00:00:00 2001 From: TAKAHASHI Shuuji Date: Sun, 22 Dec 2019 19:44:16 +0900 Subject: [PATCH 30/35] Fix a typo. --- docs/testing/cypress.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/testing/cypress.md b/docs/testing/cypress.md index d75134718..6c892032c 100644 --- a/docs/testing/cypress.md +++ b/docs/testing/cypress.md @@ -53,7 +53,7 @@ Cypressの最初のdry runを行い、Cypressのフォルダ構造を準備し npx cypress open ``` -`e2e/cypress/plugins/index.js`を次のように編集して、CypressをTypeScriptのトランスパイルようにセットアップします: +`e2e/cypress/plugins/index.js`を次のように編集して、CypressをTypeScriptのトランスパイル用にセットアップします: ```js const wp = require('@cypress/webpack-preprocessor') From 49974e28ea99c5b7a73ae193b4eb2f850a6c3a17 Mon Sep 17 00:00:00 2001 From: TAKAHASHI Shuuji Date: Fri, 27 Dec 2019 16:05:08 +0900 Subject: [PATCH 31/35] Update docs/quick/browser.md. --- docs/quick/browser.md | 42 +++++++++++++++++++++++++++++------------- 1 file changed, 29 insertions(+), 13 deletions(-) diff --git a/docs/quick/browser.md b/docs/quick/browser.md index c40e2ac7d..511f957b3 100644 --- a/docs/quick/browser.md +++ b/docs/quick/browser.md @@ -35,6 +35,9 @@ cd your-project "compilerOptions": { "sourceMap": true, "module": "commonjs", + "esModuleInterop": true, + "resolveJsonModule": true, + "experimentalDecorators": true, "target": "es5", "jsx": "react", "lib": [ @@ -65,15 +68,17 @@ cd your-project "start": "webpack-dev-server -d --content-base ./public" }, "dependencies": { - "@types/react": "16.4.2", - "@types/react-dom": "16.0.6", - "react": "16.4.1", - "react-dom": "16.4.1", - "ts-loader": "4.4.1", - "typescript": "2.9.2", - "webpack": "4.12.1", - "webpack-cli": "3.0.8", - "webpack-dev-server": "3.1.4" + "@types/react": "16.4.10", + "@types/react-dom": "16.0.7", + "clean-webpack-plugin": "0.1.19", + "html-webpack-plugin": "3.2.0", + "react": "16.4.2", + "react-dom": "16.4.2", + "ts-loader": "4.4.2", + "typescript": "3.0.1", + "webpack": "4.16.5", + "webpack-cli": "3.1.0", + "webpack-dev-server": "3.1.5" } } ``` @@ -81,11 +86,22 @@ cd your-project * すべてのリソースを含む単一の`app.js`ファイルにモジュールをバンドルするための`webpack.config.js`を作成する: ```js +const { CleanWebpackPlugin } = require('clean-webpack-plugin'); +const HtmlWebpackPlugin = require('html-webpack-plugin'); + module.exports = { entry: './src/app/app.tsx', + plugins: [ + new CleanWebpackPlugin({ + cleanAfterEveryBuildPatterns: ['public/build'] + }), + new HtmlWebpackPlugin({ + template: 'src/templates/index.html' + }), + ], output: { path: __dirname + '/public', - filename: 'build/app.js' + filename: 'build/[name].[contenthash].js' }, resolve: { extensions: ['.ts', '.tsx', '.js'] @@ -104,18 +120,18 @@ module.exports = {
- + ``` あなたのフロントエンドアプリケーションのエントリポイントである`src/app/app.tsx`: -```js +```ts import * as React from 'react'; import * as ReactDOM from 'react-dom'; -const Hello: React.SFC<{ compiler: string, framework: string }> = (props) => { +const Hello: React.FunctionComponent<{ compiler: string, framework: string }> = (props) => { return (
{props.compiler}
From 3a7d27894822fa76368bad1e7e6110efad7039fb Mon Sep 17 00:00:00 2001 From: TAKAHASHI Shuuji Date: Fri, 27 Dec 2019 16:30:10 +0900 Subject: [PATCH 32/35] Update docs/quick/nodejs.md. --- docs/quick/nodejs.md | 48 +++----------------------------------------- 1 file changed, 3 insertions(+), 45 deletions(-) diff --git a/docs/quick/nodejs.md b/docs/quick/nodejs.md index 7f7bd360c..457761e2c 100644 --- a/docs/quick/nodejs.md +++ b/docs/quick/nodejs.md @@ -19,7 +19,8 @@ TypeScriptは、Node.jsを公式にサポートしています。素早くNode.j ```json "scripts": { "start": "npm run build:live", - "build:live": "nodemon --exec ./node_modules/.bin/ts-node -- ./index.ts" + "build": "tsc -p .", + "build:live": "nodemon --watch 'src/**/*.ts' --exec 'ts-node' src/index.ts" }, ``` @@ -29,50 +30,7 @@ TypeScriptは、Node.jsを公式にサポートしています。素早くNode.j * ts-nodeは自動的にtsconfig.jsonとインストールされたTypeScriptバージョンを取得し、トランスパイルを行う * ts-nodeは出力されたJavaScriptをNode.jsで実行する -## TypeScriptのnode moduleを作成する - -* [Typecriptのnodemoduleの作成に関するレッスン](https://egghead.io/lessons/typescript-create-high-quality-npm-packages-using-typescript) - -TypeScriptで書かれたモジュールを使用することは、コンパイル時の安全性とオートコンプリートが得られるので、非常に楽しいことです。 - -高品質のTypeScriptモジュールの作成は簡単です。以下の望ましいフォルダ構造を仮定します。 - -```text -package -├─ package.json -├─ tsconfig.json -├─ src -│ ├─ All your source files -│ ├─ index.ts -│ ├─ foo.ts -│ └─ ... -└─ lib - ├─ All your compiled files - ├─ index.d.ts - ├─ index.js - ├─ foo.d.ts - ├─ foo.js - └─ ... -``` - - -* `tsconfig.json`について - * `compilerOptions`に`"outDir": "lib"`と、`"declaration": true`を設定します < これは宣言ファイルとjsファイルをlibフォルダに生成します - * `"include": ["./src / ** / *"]`を設定します < これは`src`ディレクトリからのすべてのファイルを対象に含めます - -* `package.json`について - * `"main": "lib/index"` <これはNode.jsに`lib/index.js`をロードするように指示します -  * `"types": "lib/index"` <これはTypeScriptに`lib/index.d.ts`をロードするように指示します - - -パッケージの例: -* `npm install typestyle` [for TypeStyle](https://www.npmjs.com/package/typestyle) -* 使用法:`import { style } from 'typestyle';`は、完全な型安全性を提供します - -MORE: - -* あなたのパッケージが他のTypeScriptで作られたパッケージに依存している場合は、そのまま生のJSパッケージと同様に`dependencies`/`devDependencies`/ `peerDependencies`に入れてください -* パッケージが他のJavaScript作成パッケージに依存していて、プロジェクトで型安全性を使用する場合は、それらの型定義(`@types/foo`など)を`devDependencies`に入れます。JavaScriptの型は、主なNPMの流れの*範囲外で*管理する必要があります。JavaScriptのエコシステムでは、セマンティックなバージョン管理が行われていない場合、型をあまりにも簡単に壊すので、ユーザーが型を必要とする場合は、それらに対応する`@types/foo`のバージョンをインストールする必要があります。 +And when you are ready to deploy your JavaScript application run `npm run build`. ## ボーナスポイント From 6de8ce8cbfb8ccc7b755465fbb4de38c85ef449b Mon Sep 17 00:00:00 2001 From: TAKAHASHI Shuuji Date: Fri, 27 Dec 2019 16:30:49 +0900 Subject: [PATCH 33/35] Translate docs/quick/nodejs.md. --- docs/quick/nodejs.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/quick/nodejs.md b/docs/quick/nodejs.md index 457761e2c..bf2c058d4 100644 --- a/docs/quick/nodejs.md +++ b/docs/quick/nodejs.md @@ -30,7 +30,7 @@ TypeScriptは、Node.jsを公式にサポートしています。素早くNode.j * ts-nodeは自動的にtsconfig.jsonとインストールされたTypeScriptバージョンを取得し、トランスパイルを行う * ts-nodeは出力されたJavaScriptをNode.jsで実行する -And when you are ready to deploy your JavaScript application run `npm run build`. +JavaScriptアプリケーションのデプロイの準備が完了したが、`npm run build`を実行します。 ## ボーナスポイント From 6e9b0e2020614deed53d57551acbac040d6c220d Mon Sep 17 00:00:00 2001 From: TAKAHASHI Shuuji Date: Fri, 27 Dec 2019 16:35:42 +0900 Subject: [PATCH 34/35] Create and update docs/quick/library.md. --- docs/quick/library.md | 62 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 docs/quick/library.md diff --git a/docs/quick/library.md b/docs/quick/library.md new file mode 100644 index 000000000..560b3eb38 --- /dev/null +++ b/docs/quick/library.md @@ -0,0 +1,62 @@ +## TypeScriptのnode moduleを作成する + +* [Typecriptのnodemoduleの作成に関するレッスン](https://egghead.io/lessons/typescript-create-high-quality-npm-packages-using-typescript) + +TypeScriptで書かれたモジュールを使用することは、コンパイル時の安全性とオートコンプリートが得られるので、非常に楽しいことです。 + +TypeScript modules can be consumed both in the nodejs (as is) browser (with something like webpack). + +高品質のTypeScriptモジュールの作成は簡単です。以下の望ましいフォルダ構造を仮定します。 + +```text +package +├─ package.json +├─ tsconfig.json +├─ src +│ ├─ index.ts +│ ├─ foo.ts +│ └─ ...All your source files (Authored) +└─ lib + ├─ index.d.ts.map + ├─ index.d.ts + ├─ index.js + ├─ foo.d.ts.map + ├─ foo.d.ts + ├─ foo.js + └─ ... All your compiled files (Generated) +``` + +* `src/index.ts`: Here you would export anything you expect to be consumed from your project. E.g `export { Foo } from './foo';`. Exporting from this file makes it available for consumption when someone does `import { /* Here */ } from 'example';` + +* `tsconfig.json`について + * `compilerOptions`に`"outDir": "lib"`と、`"declaration": true`と`"declarationMap" : true`を設定します < これはlibフォルダに`.js` (JavaScript) `.d.ts` (declarations for TypeSafety) and `.d.ts.map` (enables `declaration .d.ts` => `source .ts` IDE navigation)生成します + * `include: ["src"]`を設定します < これは`src`ディレクトリからのすべてのファイルを対象に含めます + +* `package.json`について + * `"main": "lib/index"` <これはNode.jsに`lib/index.js`をロードするように指示します +  * `"types": "lib/index"` <これはTypeScriptに`lib/index.d.ts`をロードするように指示します + + +パッケージの例: +* `npm install typestyle` [for TypeStyle](https://www.npmjs.com/package/typestyle) +* 使用法:`import { style } from 'typestyle';`は、完全な型安全性を提供します + +### Managing Dependencies + +#### devDependencies + +* If your package depends on another package while you are developing it (e.g. `prettier`) you should install them as a `devDependency`. This way they will not pollute the `node_modules` of your module's consumers (as `npm i foo` does not install `devDependencies` of `foo`). +* `typescript` is normally a `devDependency` as you only use it to build your package. The consumers can use your package with or without TypeScript. +* If your package depends on other JavaScript authored packages and you want to use it with type safety in your project, put their types (e.g. `@types/foo`) in `devDependencies`. JavaScript types should be managed *out of bound* from the main NPM streams. The JavaScript ecosystem breaks types without semantic versioning too commonly, so if your users need types for these they should install the `@types/foo` version that works for them. If you want to guide users to install these types you can put them in `peerDependencies` mentioned next. + +#### peerDependencies + +If your package depends on a package that it heavily *works with* (as opposed to *works using*) e.g. `react`, put them in `peerDependencies` just like you would with raw JS packages. To test them locally you should also put them in `devDependencies`. + +Now: +* When you are developing the package you will get the version of the dependency you specified in your `devDependencies`. +* When someone installs your package they will *not* get this dependency (as `npm i foo` does not install `devDependencies` of `foo`) but they will get a warning that they should install the missing `peerDependencies` of your package. + +#### dependencies + +If your package *wraps* another package (meant for internal use even after compilation) you should put them in `dependencies`. Now when someone installs your package they will get your package + any of its dependencies. From 5c01648873fdd66d7dee6af301698c103bbcbfd2 Mon Sep 17 00:00:00 2001 From: TAKAHASHI Shuuji Date: Fri, 27 Dec 2019 17:07:56 +0900 Subject: [PATCH 35/35] Translate docs/quick/library.md. --- docs/quick/library.md | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/docs/quick/library.md b/docs/quick/library.md index 560b3eb38..19eac3411 100644 --- a/docs/quick/library.md +++ b/docs/quick/library.md @@ -4,7 +4,7 @@ TypeScriptで書かれたモジュールを使用することは、コンパイル時の安全性とオートコンプリートが得られるので、非常に楽しいことです。 -TypeScript modules can be consumed both in the nodejs (as is) browser (with something like webpack). +TypeScriptのモジュールは、Node.jsではそのまま使用でき、ブラウザでもWebpackなどを使うことで利用できるようになります。 高品質のTypeScriptモジュールの作成は簡単です。以下の望ましいフォルダ構造を仮定します。 @@ -26,37 +26,37 @@ package └─ ... All your compiled files (Generated) ``` -* `src/index.ts`: Here you would export anything you expect to be consumed from your project. E.g `export { Foo } from './foo';`. Exporting from this file makes it available for consumption when someone does `import { /* Here */ } from 'example';` +* `src/index.ts`: ここでは、他のプロジェクトから使用できるようにしたいすべてのものをexportします。たとえば、`export { Foo } from './foo';`などを書きます。このファイルからexportしたオブジェクトは、このライブラリを使用する他の人が `import { /* Here */ } from 'example';` のように書いてimportすることができるようになります。 * `tsconfig.json`について - * `compilerOptions`に`"outDir": "lib"`と、`"declaration": true`と`"declarationMap" : true`を設定します < これはlibフォルダに`.js` (JavaScript) `.d.ts` (declarations for TypeSafety) and `.d.ts.map` (enables `declaration .d.ts` => `source .ts` IDE navigation)生成します + * `compilerOptions`に`"outDir": "lib"`と、`"declaration": true`と`"declarationMap" : true`を設定します < これは、libフォルダに`.js` (JavaScript)と`.d.ts` (型安全性のための型宣言)と`.d.ts.map` (このファイルは、IDE上で`declaration .d.ts` => `source .ts`というナビゲーションを可能にします)が生成されます * `include: ["src"]`を設定します < これは`src`ディレクトリからのすべてのファイルを対象に含めます * `package.json`について - * `"main": "lib/index"` <これはNode.jsに`lib/index.js`をロードするように指示します -  * `"types": "lib/index"` <これはTypeScriptに`lib/index.d.ts`をロードするように指示します + * `"main": "lib/index"` < これはNode.jsに`lib/index.js`をロードするように指示します +  * `"types": "lib/index"` < これはTypeScriptに`lib/index.d.ts`をロードするように指示します パッケージの例: * `npm install typestyle` [for TypeStyle](https://www.npmjs.com/package/typestyle) * 使用法:`import { style } from 'typestyle';`は、完全な型安全性を提供します -### Managing Dependencies +### Dependenciesの管理 #### devDependencies -* If your package depends on another package while you are developing it (e.g. `prettier`) you should install them as a `devDependency`. This way they will not pollute the `node_modules` of your module's consumers (as `npm i foo` does not install `devDependencies` of `foo`). -* `typescript` is normally a `devDependency` as you only use it to build your package. The consumers can use your package with or without TypeScript. -* If your package depends on other JavaScript authored packages and you want to use it with type safety in your project, put their types (e.g. `@types/foo`) in `devDependencies`. JavaScript types should be managed *out of bound* from the main NPM streams. The JavaScript ecosystem breaks types without semantic versioning too commonly, so if your users need types for these they should install the `@types/foo` version that works for them. If you want to guide users to install these types you can put them in `peerDependencies` mentioned next. +* パッケージの開発中にのみ他のパッケージに依存している場合(例: `prettier`)、依存するパッケージは`devDependency`に追加します。こうすることで、あなたのパッケージを使用するユーザーの`node_modules`には開発用の依存パッケージをインストールしないようにできます(`npm i foo`というコマンドを実行した場合には、`foo`のdevDependencies`はインストールされないためです)。 +*`typescript`は通常パッケージのビルド時にのみ使用されるため、`devDependency`に追加します。パッケージのユーザーはTypeScriptなしでもあなたのパッケージを利用できます。 +* あなたのパッケージがJavaScriptで作られた他のパッケージに依存していて、あなたのプロジェクトでは型安全性を活用したい場合には、依存しているパッケージの型パッケージ(例: `@types/foo`)を`devDependencies`に追加してください。JavaScriptの型は、メインのNPMエコシステムの*外側で*管理されています。JavaScriptエコシステムでは、セマンティックバージョニングを使用していない場合には特に、型が破壊されるのは日常茶飯事です。そのため、ユーザーが型を使用したい場合には、自分でパッケージに適したバージョンの型`@types/foo`をインストールする必要があります。型パッケージをインストールするようにユーザーに支持したい場合には、次のセクションに示すように、パッケージを`peerDependencies`に追加します。 #### peerDependencies -If your package depends on a package that it heavily *works with* (as opposed to *works using*) e.g. `react`, put them in `peerDependencies` just like you would with raw JS packages. To test them locally you should also put them in `devDependencies`. +あなたのパッケージが依存するパッケージで、(*インストールしないと動作しない*というわけではなく)同時にインストールしたときに*よりよく動作する*というようなパッケージがある場合には、生のJSパッケージでするのと同じように、そのパッケージを`peerDependencies`に追加してください(たとえば、`react`など)。ローカルでテストする場合にも、`devDependencies`に追加する必要があります。 -Now: -* When you are developing the package you will get the version of the dependency you specified in your `devDependencies`. -* When someone installs your package they will *not* get this dependency (as `npm i foo` does not install `devDependencies` of `foo`) but they will get a warning that they should install the missing `peerDependencies` of your package. +このように設定を行うことで、次のように動作するようになります。 +* パッケーの開発中は、`devDependencies`で指定したバージョンのパッケージがインストールされます。 +* 他のユーザーがあなたのパッケージをインストールした場合には、`devDependencies`で指定されたパッケージはインストール*されません*が、あなたのパッケージの`peerDependencies`に指定されているパッケージが存在しない場合には、ユーザーにそのパッケージをインストールするべきであるという警告が表示されます。 #### dependencies -If your package *wraps* another package (meant for internal use even after compilation) you should put them in `dependencies`. Now when someone installs your package they will get your package + any of its dependencies. +あなたのパッケージが他のパッケージの*ラッパー*である場合(つまり、TypeScriptのコンパイル後にも内部で他のライブラリを使用する場合)には、そのパッケージは`dependencies`に追加しなければなりません。そうすることで、あなたのパッケージをインストールしたユーザーはあなたのパッケージに加えて、その依存パッケージを同時にインストールできるようになります。