TypeScriptの紹介
公開: 2020-10-29私がこれまでにプログラムした最初の言語はCとJavaです。 これらの言語では、変数を定義するたびに、そのタイプを指定する必要があります。 別のタイプの値を割り当てようとすると、コンパイラは次のように文句を言います。
// main.c int main() { int x = "two"; return 0; } > cc main.c -o main // warning: initialization makes integer from pointer without a cast問題は、私の経験不足のために、コンパイラーから受け取った苦情の多くが不可解で複雑に見えたことです。 そのため、最終的には、コンパイラを自分の創造性を制限するツールと見なしましたが、実際には、そこにいるパートナーが支援することになっています。

キャリアの後半では、JavaScriptやPHPなど、強い型付けをせずにいくつかのプログラミング言語を使い始めました。 私はそれらがかなりクールだと思いました:厄介なコンパイラを扱う必要なしに物事を素早くプロトタイプ化することは非常に簡単でした。
ご存知のように、WordPressのベースとなるプログラミング言語はPHPとJavaScriptです。 これは、コンパイラがあなたの後ろを監視することなく、プラグインとテーマをコーディングすることにおそらく慣れていることを意味します。 それはあなた、あなたのスキル、そしてあなたの創造性だけです。 まあ、そしてこのようなエラー:
const user = getUser( userId ); greet( user.name ); // Uncaught TypeError: user is undefined コード内のundefinedのようなバグにうんざりしている場合は、ワークフローにコンパイラを追加するときが来ました。 TypeScriptとは何か、そしてそれによってソフトウェアの品質を数桁向上させる方法を見てみましょう。
TypeScriptとは何ですか
TypeScriptは、強力で静的な型付けを追加することを目的として作成されたJavaScriptベースのプログラミング言語です。 TypeScriptタイプを使用すると、オブジェクトと変数の形状を記述できるため、より適切に文書化され、より堅牢なコードが得られます。 TypeScript自体が、私たちが行うすべてのことを検証する責任があります。
設計どおり、TypeScriptはJavaScriptのスーパーセットです。 これは、プレーンJavaScriptで記述されたコードは、定義上、有効なTypeScriptでもあることを意味します。 ただし、その逆は当てはまりません。TypeScript固有の機能を使用する場合、結果のコードは、トランスパイルするまで有効なJavaScriptではありません。
TypeScriptのしくみ
TypeScriptがどのように機能するかを理解するために、そのPlaygroundを使用します。これは、TypeScriptコードを記述し、コンパイラーがそれについて教えてくれることを確認できる小さなエディターです。
JavaScriptのスーパーセットであるため、TypeScriptコードの記述は非常に簡単です。 基本的に次のJavaScriptコード:
let user = "David"; let age = 34; let worksAtNelio = true; console.log( user, age, worksAtNelio );TypeScriptコードでもあります。 TypeScript Playgroundにコピーして貼り付けると、コンパイルされることがわかります。 それで、それの何がそんなに特別なのですか? もちろん、そのタイプ。 JavaScriptでは、次のことができます。
let user = "David"; let age = 34; let worksAtNelio = true; user = { name: "Ruth" }; console.log( user, age, worksAtNelio );しかし、それはTypeScriptでエラーを引き起こします。 Playgroundで試してみると、次のエラーが表示されます。
Type '{ name: string; }' is not assignable to type 'string'.それで、それはどういうことですか?
TypeScriptは、変数のタイプを自動的に推測できます。 つまり、「ねえ、この変数は文字列です」(または数値、ブール値など)を明示的に伝える必要はありません。 代わりに、最初に与えられた値を調べ、それに基づいてそのタイプを推測します。

この例では、変数userを定義したときに、テキスト文字列"David"を割り当てたため、TypeScriptは、 userが文字列であることを認識します(常にそうである必要があります)。 問題は、少し後に、値が文字列"Ruth"である単一のプロパティ( name )を持つオブジェクトを割り当てることによって、 user変数のタイプを変更しようとすることです。 明らかに、このオブジェクトは文字列ではないため、TypeScriptは文句を言い、割り当てを実行できないことを通知します。
これを修正するための2つの可能なルートがあります:
// Option 1 let user = "David"; user = "Ruth"; // OK. // Option 2 let user = { name: "David" }; user = { name: "Ruth" };変数の型を定義するときに明示的にしましょう
しかし、型推論は私たちを助けるためだけにあります。 必要に応じて、TypeScriptに変数の型を明示的に伝えることができます。
let user: string = "David"; let age: number = 34; let worksAtNelio: boolean = true; console.log( user, age, worksAtNelio );これは、TypeScriptによって推測されたタイプとまったく同じ結果をレンダリングします。 さて、これは疑問を投げかけます:TypeScriptがタイプを自動的に推測できるのなら、なぜこの機能が必要なのですか?
一方では、型を明示的に指定すると、コードをより適切に文書化するのに役立ちます(これは次のセクションでさらに明確になります)。 一方、型推論システムの限界を解決することができます。 そうです、あなたはその権利を読んでいます。推論があまり良くなく、TypeScriptができる最善のことは、「まあ、この変数が正確に何であるかわかりません。 何でもいいと思います!」
次の例を考えてみましょう。
const getName = ( person ) => person.name; let david = { name: "David", age: 34 }; console.log( getName( david ) ); // Parameter 'person' implicitly has an 'any' type. この場合、パラメーターを受け取り、値を返すgetName関数を定義しています。 このような単純な機能で想定していることがいくつあるかに注目してください。nameというnameのプロパティが少なくとも1つあるオブジェクト( person )を想定しています。 ただし、この関数を呼び出す人が適切に使用するという保証はありません。 しかし、たとえそうだとしても、この関数の結果のタイプが何であるかはまだわかりません。 確かに、名前は文字列になると思うかもしれませんが、あなたは人間であり、その単語の意味を理解しているので、それを知っているだけです。 ただし、次の例を見てください。
getName( "Hola" ); // Error getName( {} ); // Returns undefined getName( { name: "David" } ); // Returns a string getName( { name: true } ); // Returns a boolean関数を呼び出すたびに、異なる結果が得られます。 したがって、TypeScriptが私たちの後ろを監視しているにもかかわらず、私たちはまだ古典的なJavaScriptの問題に直面しています。この関数は何でも受け取ることができ、何でも返すことができます。


ご想像のとおり、解決策は関数に明示的に注釈を付けることです。
独自のタイプを定義する
ただし、その前に、別のTypeScript機能であるカスタムデータ型を見てみましょう。 これまでのところ、ほとんどすべての例で、文字列、数値、ブール値などの基本的な型を使用していましたが、これは非常に理解しやすいと思います。 オブジェクトのような、より複雑なデータ構造も見ました。
let david = { name: "David", age: 34 };しかし、TypeScriptによって推測されるように、そのタイプにはあまり注意を払っていませんでしたね。 私たちが見たのは、入力の不一致による無効な割り当ての例です。
let user = "David"; user = { name: "Ruth" }; // Type '{ name: string; }' is not assignable to type 'string'.これはどういうわけか、オブジェクトのタイプが「 {name:string;} 」であることをほのめかしました。これは、「これは、タイプstringのnameというプロパティを持つオブジェクトです」と読むことができます。 それがオブジェクトタイプの定義方法である場合、以下が有効なTypeScriptである必要があります。
let david: { name: string, age: number } = { name: "David", age: 34 };確かにそうです。 しかし、あなたはそれが便利ではないことに同意するでしょう。 幸い、TypeScriptで新しい型を作成できます。
一般に、カスタムタイプは基本的に、カスタム名を持つ通常のTypeScriptタイプです。
type Person = { name: string; age: number; }; let david: Person = { name: "David", age: 34 }; かっこいいね? Personタイプができたので、 getName関数に簡単に注釈を付けて、入力パラメーターのタイプを明確に指定できます。
const getName = ( person: Person ) => person.name; そして、この簡単な更新により、TypeScriptに多くの情報が提供されます。 たとえば、 Personオブジェクトのname属性も文字列であることが確実にわかっているため、この関数の結果タイプは文字列であると推測できます。
let david: Person = { name: "David", age: 34 }; let davidName = getName( david ); davidName = 2; // Type 'number' is not assignable to type 'string'.ただし、いつものように、必要に応じて結果タイプに明示的に注釈を付けることができます。
const getName = ( person: Person ): string => person.name;TypeScriptタイプのその他の機能…
最後に、TypeScriptで独自の型を定義すると、メリットが得られる興味深い機能をいくつか紹介したいと思います。
TypeScriptは、変数に値を割り当てる際に非常に要求が厳しくなります。 特定の変数のタイプを明示的に定義した場合、そのタイプに完全に一致する値のみを割り当てることができます。 いくつかの例でそれを見てみましょう:
type Person = { name: string; age: number; }; let david: Person = { name: "David", age: 34 }; // OK let ruth: Person = { name: "Ruth" }; // Property 'age' is missing in type '{ name: string; }' but required in type 'Person' let toni: Person = { name: "Toni", age: 35, gender: "M" }; // Type '{ name: string; age: number; gender: string; }' is not assignable to type 'Person'. Object literal may only specify known properties, and 'gender' does not exist in type 'Person'. ご覧のとおり、 Person変数は、 Personタイプに完全に準拠するオブジェクトのみを受け入れます。 一部の属性が欠落している場合( ruthにageがない場合)、または型に含まれている属性よりも多くの属性がある場合( toniにはgenderがあります)、TypeScriptは文句を言い、型の不一致エラーをトリガーします。
しかし、関数の呼び出しについて話している場合は、状況が異なります。 関数の引数の型は正確な要件ではありませんが、パラメーターが準拠する必要のある最小のインターフェースを指定します。 私は知っています、私は知っています、それはあまりにも抽象的です。 次の例を見てみましょう。これにより、状況がより明確になると思います。
type NamedObject = { name: string; }; const getName = ( obj: NamedObject ): string => obj.name; const ruth = { name: "Ruth" } getName( ruth ); // OK const david = { name: "David", age: 34 }; getName( david ); // OK const toni = { firstName: "Toni" }; getName( toni ); // Argument of type '{ firstName: string; }' is not assignable to parameter of type 'NamedObject'. Property 'name' is missing in type '{ firstName: string; }' but required in type 'NamedObject'. ご覧のとおり、 getName関数をもう少し一般的なものとして再定義しました。NamedObjectオブジェクト、つまり、 name型のnameという属性が必要なオブジェクトを受け取るようになりました。 この定義を使用すると、 ruthとdavidがこの要件に完全に一致することがわかります(どちらもname属性を持っています)が、 toniはexpecte属性nameを持っていないため一致しません。
結論
TypeScriptは、静的な型定義を追加することでJavaScriptを拡張するプログラミング言語です。 これにより、処理するデータをより正確に定義でき、さらに重要なことに、エラーを早期に検出するのに役立ちます。
TypeScriptを開発スタックに統合するコストは比較的小さく、段階的に実行できます。 すべてのJavaScriptコードは、定義上、TypeScriptであるため、JavaScriptからTypeScriptへの切り替えは自動的に行われます。タイプを追加し、コードを1ステップずつ装飾することができます。
この投稿が気に入って、もっと知りたい場合は、共有して、下のコメントセクションで知らせてください。
UnsplashのKing'sChurchInternationalによる注目の画像。
