サイト製作の方が多い私の業務ではTypeScriptの恩恵を受けれているのかなんとも言えないのが正直なところです。
頑張って書いた型もanyばっかりにいつの間にか変わってしまっていることもしばしば。。。
JSDocで十分っておっしゃる方の多くいらっしゃる私の環境での戦いはあまりに辛いなと最近思っております。
一年ほど前からTypeScriptの学習に励んでおりまして、業務でもしばしば利用しておりました。
学習スタートしたきっかけは、僕の担当業務範囲拡大が主な理由です。データを扱ったシステマチックなサイトやサービスの開発が目立ったことと、自分一人で開発することの方が多かったので導入もしやすいと思ったからです。
あと、新しいバージョンのJavaScriptを利用し続ける方が効率的に開発できますし、かつ安全にコードが書いていける方がコード品質を担保できるなどメリットしか感じなかったことから学習しながらほとんどの開発に導入していました。
開発環境に用いるtsconfigやeslintをセットしていくとこまでは良かったのですが、それからがかなり大変でしたww
##必要?
決して必要ではないと思います。
型定義することも考えて開発していくこと自体にコストがかかりますし、アニメーションを作る際は僕は正直いらないと思いました。
データを扱ったアプリやサービスなど運用や更新、一定のルールを決めて開発をしていく際は大変有効だと思います。
##メリットとデメリット
メリハリを付けてチームで型付けのルールなどのコニュニケーションに使用することをおすすめします。
あと、コード品質や運用面など開発後のことも視野に入れていたり、中規模くらいの開発にはうってつけかと思いますし、型の強度は自由に決めれます。
###メリット
1、最新技術を常に使える
2、javascriptコードを安全にしてくれる
3、コンパイル時にエラーを検知してくれる
4、コード品質と理解容易性の向上
5、あまり知らなくても導入できる
###デメリット
1、gulpに入れるとスピードがかなり落ちる
2、ライブラリに型がない場合自分で作らないといけない
3、メリハリを付けないとコード量が多い分混雑しているような品質になってしまう
4、javascript初級者の方にはなかなかハードルが高い
###なので
gulpやwebpackには初めは入れていたのですが、あまりにも遅いのでやめました。
moduleとcomponentsと各ページスクリプトもしくはapp.jsにのみにしており、
メリハリ必須で特にデータを扱う箇所は割と型定義は多めでアニメーションの箇所は緩めにしています。
##様々な型
###早期returnやis
を使ったガード節やType Guard
function greet(name?: string){
if(name === undefined) return "hello"
return `Hello ${name.toUpperCase()}`
}
console.log(greet())
console.log(greet("TypeScript"))
/**
* name?: string
* ?をつけると自動的にundefinedつく
*/
//"is"は型の絞り込みができる
const isString = (arg: any):arg is string => {
console.log(typeof arg === "string")
return arg
}
const foo = "foo" as any
if(isString(foo)){
console.log(typeof foo)//string
}
###意図していないオブジェクトの代入を防ぐ
type User = {
age?: number;
name?: string;
};
function registerUser(user: User) {
console.log(user);
}
const user = {
age: 33,
name: "masaru",
gender: "male"
};
const user01 = {
director: "maki",
designer: "miki"
};
//Weak type
/**
* 意図していないオブジェクトの代入を防ぐ
*/
registerUser(user);
registerUser(user01); // error
/**
* プロパティがオプショナルであるが引数が必要
* optional 選択の
*/
registerUser({}); //no error
registerUser(); //error
/*存在しない値に対しては過剰に検査します。*/
registerUser({// error
age: 33,
name: "masaru",
gender: "male"
});
registerUser({...{//no error
age: 33,
name: "masaru",
gender: "male"
}});
###型を絞り込む
type User = { name: string };
type UserA = User & { gender: "male" | "femal" | "other" };
type UserB = User & { graduate: string };
const users: (UserA | UserB)[] = [
{ name: "Taro", gender: "male" },
{ name: "masaru", graduate: "oosaka" }
];
const filterUserSample = users.filter(user => "graduate" in user);
console.log(filterUserSample);
//絞りこめていない
//const filterUserSample: (UserA | UserB)[]
function filterUserA(user: UserA | UserB): user is UserA {
return "gender" in user;
}
function filterUserB(user: UserA | UserB): user is UserB {
return "graduate" in user;
}
const filterUsersA = users.filter(filterUserA);
console.log(filterUsersA); // const filterUsersA: UserA[]
const filterUsersB = users.filter(filterUserB);
console.log(filterUsersB); // const filterUsersB: UserB[]
###Promiseの型推論
//アノテーション付き :TypeAnnotation
//アサーション(宣言)付き <string>
//https://typescript-jp.gitbook.io/deep-dive/type-system
//https://typescript-jp.gitbook.io/deep-dive/future-javascript/async-await
function promise01Annotation(duration: number): Promise<string> {
return new Promise(resolve => {
setTimeout(() => {
console.log(resolve(`${duration}ms ${Date.now()}`));
}, duration);
});
}
const promise03 = async () => {
let message = await promise01Annotation(2000);//let message: string
return message;
};
console.log(promise03());//const promise02: () => Promise<string>
function promise01(duration: number) {
return new Promise(resolve => {
setTimeout(() => {
console.log(resolve(`${duration}ms ${Date.now()}`));
}, duration);
});
}
promise01(1000).then(res => {
console.log(res)
});
const promise02 = async () => {
let message = await promise01(2000);//let message: unknown
return message;
};
console.log(promise02());//const promise02: () => Promise<unknown>
##Generics
変数のような機能を果たしてくれます。
genericsは結構重要な箇所かと思います。
###基本な利用
多分かなと思います。
interface InputValue<T> {
value: T;
}
const val01: InputValue = { value: "1" }; // error
const val02: InputValue<string> = { value: "val" };
const val03: InputValue<number> = { value: 33 };
###extends
指定可能な型を絞れる
interface InputValue<T extends string | number> {
value: T;
}
const val01: InputValue<boolean> = { value: true }; // error
const val02: InputValue<string> = { value: "val" };
const val03: InputValue<number> = { value: 33 };
##関数
function valueFunc01<T>(props: T) {
return {value: props}
}
const VAL01 = valueFunc01(1)
//アサーションによる明示的な型付与
const VAL01As01 = valueFunc01(1 as number | null)
const VAL01As02 = valueFunc01("test" as string | null)
//extendsを利用した制約された型付与
function valueFunc02<T extends string>(props: T) {
return {value: props}
}
const VAL02 = valueFunc02("val")
以上です。
抜粋的に載せましたが基本的な内容だと思います。
この先にもまだまだありますし、深いです。
TypeScript必須的な情報は多くありますが、必要ない案件では必要ないと思います。
流行にのりたいだけで始めるのはやめた方がいいです。大事なのは案件を無事やりとげることです。
僕は適材適所で利用していきしっかり恩恵とメリットを感じらる状態がベストだと思います。
##関連サイトや本
TypeScript本サイト
TypeScript Deep Diveの日本語版
実践TypeScript