#挨拶
ポートフォリオ作成で言語・技術で以前から興味のあったTypeScriptを使うことにしたので勉強してみました。
間違っている解釈などがあればご指摘いただけると幸いです。
TypeScript
github-typescript deep drive
静的型付けを行うことで大規模な開発にも適した記法ができるようになった
node.jsによる実行
tec <ファイル名.ts>
typescriptファイルをjsファイルに変換
node <ファイル名.js>
ファイルを実行
静的型付け
先に変数の型を決めておく記法
integer型にstring型などができなくなる
let x:number = 10;
// out x= 'string';
let x = 1;
型の種類
- number
- string
- boolean
- any
// let 変数名:型の種類;
// let 変数名:型の種類 = 値;
let num:number = 100;
// 配列の宣言
let resulets: number[];
let resulets: number[] = [10,9,8];
number = [7,6];
列挙型(Enums)
列挙型は,関連する値の集合を編成する方法です。
列挙型は数値ベースです。これは,数値を列挙型のインスタンスに割り当てることができることを意味し、numberと互換性のあるものもそうです。
数値列挙型
下のsumpleのenum値はnumberなので、数値列挙型と呼んでいる
enum CardSuit{
Clubs,
Diamonds,
Hearts,
Spades
}
// sample usage
let card = CardSuit.Clubs;
// Safety Error:string is not assiggnable to type 'Card suit'
// Typeが異なるためerrorとなる
card = 'not a member of card suit';
数値列挙型と文字列
enum Tristate {
False,
True,
Unknown
}
console.log(Tristate[0]); // "False"
console.log(Tristate["False"]); // 0
console.log(Tristate[Tristate.False]);
var Tristate;
(function (Tristate) {
Tristate[Tristate["False"] = 0] = "False";
Tristate[Tristate["True"] = 1] = "True";
Tristate[Tristate["Unknown"] = 2] = "Unknown";
})(Tristate || (Tristate = {}));
console.log(Tristate[0]); // "False"
console.log(Tristate["False"]); // 0
console.log(Tristate[Tristate.False]); //”False"
数値列挙型に関連づけられた数値を変更する
デフォルトでは列挙型は先頭の値に0~数値が関連づけられる。
ただし、任意の列挙型メンバーに関連づけられた番号を、それに特に割り当てて変更することはできる。
enum Color{
Red = 3; //3
Blue; //4
Green; //5
}
ヒント:私はいつも最初の列挙型を= 1で初期化することによって、列挙型の値を安全にtruthyチェックできるようにします。
フラグとしての数値列挙型(Number Enus as flags)
列挙型の優れた使い方は、列挙型をフラグとして使用することです。
フラグを使用すると一連の条件から特定の条件が真であるかどうかを確認できます。
enum animals{
None = 0; // 0
HasClaws = 1 << 0; // 1
CanFly = 1 << 1; // 10
EatsFish = 1 << 2; // 100
Endangered = 1 << 3;// 1000
}
上の例だと、ビット演算子を利用して0,1,10,100,1000という2進数を作った。
これにより、ビット演算子|(or) &(and) ~(not)を使って、オペランドに1がある時animalという判定が可能になる。
enum AnimalFlags {
None = 0,
HasClaws = 1 << 0,
CanFly = 1 << 1,
}
function printAnimalAbilities(animal) {
var animalFlags = animal.flags;
if (animalFlags & AnimalFlags.HasClaws) {
console.log('animal has claws');
}
if (animalFlags & AnimalFlags.CanFly) {
console.log('animal can fly');
}
if (animalFlags == AnimalFlags.None) {
console.log('nothing');
}
}
let animal = { flags: AnimalFlags.None };
console.log(animal); //{ flags : 0}
console.log(animal.flags); // 0
console.log(AnimalFlags.None); // 0
printAnimalAbilities(animal); // nothing
animal.flags |= AnimalFlags.HasClaws;
console.log(animal.flags); // 1
printAnimalAbilities(animal); // animal has claws
animal.flags &= ~AnimalFlags.HasClaws;
console.log(animal.flags); // 0
printAnimalAbilities(animal); // nothing
animal.flags |= AnimalFlags.HasClaws | AnimalFlags.CanFly;
printAnimalAbilities(animal); // animal has claws, animal can fly
注:フラグを組み合わせて、列挙型定義内の便利なショートカットを作成することができます。EndangeredFlyingClawedFishEatingは以下のようになります:
enum AnimalFlags {
None = 0,
HasClaws = 1 << 0,
CanFly = 1 << 1,
EatsFish = 1 << 2,
Endangered = 1 << 3,
EndangeredFlyingClawedFishEating = HasClaws | CanFly | EatsFish | Endangered,
}
文字列列挙型(String Enums)
メンバの値がStringのEnumを見ていく。
export enum EvidenceTypeEnum{
UNKNOWN = '',
PSSPORT_VISA = 'passport_visa',
PASSPORT = 'passport',
SIGHTED_STUDENT_CARD = 'sighted_tertiary_edu_id',
SIGHTED_KEYPASS_CARD = 'sighted_keypass_card',
SIGHTED_PROOF_OF_AGE_CARD = 'sighted_proof_of_age_card'
}
export 文は、モジュールから関数、オブジェクト、プリミティブ値をエクスポートするための JavaScript モジュールを作成するときに使用し、これらは別のプログラムから import 文で利用することができます。
export
これらは意味を持ち、デバックが可能な文字列を提供するのでデバックする。
これらの値を使用して簡単な文字列の比較を行うことができる。例えば、
//Where 'someStringFromBackend' will be ' ' | 'passport_visa' | 'passport ' ...etc
const value = someStringFromBackend as EvidenceTypeEnum;
//Sample use in code
if(value === EvidenceTypeEnum.PASSPORT){
console.log('You provided a passport');
console.log(value); // 'passport'
}
###定数列挙型(Const Enums)
const enumとしてマークすることでパフォーマンスが向上する。
const enum Tristate{ //enum ⇨const enum
False,
True,
Unknown
}
let lie = Tristate.False;
javascriptにコンパルした時、
// enum の時
let lie = Tristate.False;
// const enum の時
let lie = 0;
列挙型のあらゆる用途をインライン化する(実行環境に移す前に展開することで実行時にenumメンバーを検索する必要がなくなる。)⇨プログラミングをしやすく、実行時に早くなる。
定数列挙型に対する--preserveConstEnums(Const enum preserveConstEnums)
インライン化には明らかなパフォーマンス上の利点があります。実行時にTristate変数がないという事実は、実行時に実際には使用されないJavaScriptを生成しないことによって、コンパイラを助けることです。しかし、それでも先程のように数値型と文字列型を相互に検索できる列挙型を生成したい場合があるかもしれません。この場合、コンパイラフラグ--preserveConstEnumsを使用することができます。またvar Tristate定義を生成するので、実行時にTristate["False"]やTristate[0]を手動で使用することができます。これはインライン展開には決して影響しません。
静的関数を持つ列挙型(Enum with static functions)
宣言enumとnamespaceを合体させて、静的メソッドを列挙型に追加することができる。以下は、静的メンバーisBusinessDayを列挙型Weekdayに追加する例を示す。
静的メソッドはクラスのインスタンスから呼び出せません。その代わりに、静的メソッドはクラスそのものから呼び出します。
enum Weekday{
Monday,
Tuesday,
Wednesday,
Thursday,
Friday,
Saturday,
Sunday
}
namespace Weekday{ //enumと同じ名前をつける。
export function isBusinessDay(day:Weekday){
switch(day){
case Weekday.Saturday:
case Weekday.Sunday:
return false;
default:
return true;
}
}
}
const mon = Weekday.Monday;
const sun = Weekday.Sunday;
console.log(Weekday.isBusinessDay(mon)); //true
console.log(Weekday.isBusinessDay(sun)); //false
関数宣言
function add(a :number,b :numbner):number{
return a + b;
}
console.log(add(5, 3)); // 8
function add(a :number,b? :numbner):number{
if(b){
return a + b ;
}else{
return a + a ;
}
}
console.log(3); // 6
function add(a :number,b :numbner = 10):number{
return a + b;
}
console.log(3); // 13
アロー関数式
let add = (a: numbner,b: number):number=>{
return a + b;
}
let add = (a: number,b: number):number=> a+b;
console.logg(add(10 + 10));
関数のオーバーロード
function add(a: number, b: number): number; // シグネチャ
function add(a: string, b: string): string;
function add(a: any, b: any): any {
if (typeof a === "string" && typeof b === "string") {
return a + " " + b;
}
return a + b;
}
console.log(add(5, 3)); // 8
console.log(add("hello", "world")); // hello world
// console.log(add("hello", 3)); //error
クラス
- public //外から呼べる
- protected //継承クラス内でのみアクセス可能
- private //クラス内からアクセス可能
class User{
/*
public name:stirng;
constructor(name: string){
this.name = name;
}
*/
//上記を短くした書き方
constructor(public name: string){
}
sayHi(): void{ //void 返り値なし
console.log("hi! i am "+ this.name);
}
}
let tom = new User('tom');
console.log(tom.name);
tom.sayHi();
privateに対してgetter,setter
private変数の先頭には分かりやすいように_をつける.
注意:get setはコンパイル時に tsc <ファイル名.ts> -t es5をつける
class User{
constructor(private _name: string){
}
get name(){
return this._name;
}
set name(newValue:string){
this._name = newValue;
}
}
let tom = new User('tom');
console.log(tom.name);
tom.name = 'TOM';
console.log(tom.name);
クラスの継承とprotected
- extends 継承
- protected 継承先とクラス内のみアクセス可能
継承
元となるクラスの差分のみを記述して新たなクラスを宣言することができる。継承元をスーパークラス、新たに定義されるクラスをサブクラスという。
オーバーライド
親クラスのメンバを子クラスで上書きすること
【TypeScript】super()の使い方理解する。(親Classのメソッドを使用、値を渡す)
class User{
constructor(protected _name: string){
}
sayHi(): void{ //void 返り値なし
console.log("hi! i am "+ this._name);
}
}
class AdminUser extends User {
private _age: number;
constructor(_name: string, _age: number){
super(_name); //スーパークラスと同じ操作はsuperを使って呼び出し
this._age=_age;
}
public sayHi():void{ //オーバーライド
console.log("my age:" + this._age);
console.log("my name" + this._name);
super.sayHi();
}
}
let bob = new AdiminUser("BOB",23);
bob.sayHi();
静的メンバ
インスタンスに紐づいたメソッドでなく、クラスに紐づいたメソッド。クラス名.メソッド名()で呼び出し可能
class User{
name:string;
constructor(name:string){
this.name = name;
User.count++;
}
static count: number=0;
static showDescription():void{
console.log("this class is about users");
}
}
let tom = new User("tom");
let bob = new User("bob");
console.log(User.count); //インスタンス関係なく、クラス名.で呼び出し可能
User.showDescription();
インターフェースと構造的部分型
interface
まとめて型を宣言できる。関数の引数と同じように?をつけてoptionにもできる
interface Result{ //Result型を宣言
a: number;
b: number;
}
function getTotal(result :Result){
return result.a + result.b;
}
let result ={
a: 32,
b: 58,
c: "hello"
};
//構造的部分型はある型(今回はResult型)のプロパティを持ってさえばその型とみなすため、エラーにならない。
console.log(getTotal(result));
インターフェースの継承
インターフェースは多重継承可能
interface SpringResult {
a: number;
}
interface FallResult {
b: number;
}
// 多重継承
interface FinalResult extends SpringResult, FallResult {
// finalをオプションに
final?: number;
}
function getTotal(result: FinalResult) {
if (result.final) {
return result.a + result.b + result.final;
} else {
return result.a + result.b;
}
}
var result = {
a: 32,
b: 58
};
console.log(getTotal(result));
インターフェースを実装する
interfaceはクラスと組み合わせると、インターフェースの中のプロパティを必ずクラスの方で実装してくださいという意味になる。
インターフェースは抽象クラスの仲間であり、親インターフェースで未定だったメソッドなどを確実に実装させる。
interface GameUser {
score: number;
showScore(): void;
}
class User implements GameUser {
name: string;
score: number = 0; //宣言
constructor(name: string) {
this.name = name;
}
sayHi(): void {
console.log("hi! i am " + this.name);
}
showScore(): void { //親インターフェースの未定のメソッドをオーバーライドして実装
console.log("score " + this.score);
}
}
Generics (ジェネリクス)
抽象化されたデータ型
仮引数や戻り値の型を実行時に決定できるようにする。(同じ処理をstring型でもnumber型でもやりたい時に便利)
// 仮引数や戻り値の型は宣言せずに、Tを置く(Tは慣習)
function getArray<T>(value: T): T[]{
return [value,value,value];
}
// 呼び出し時に引数と型を指定する
console.log(getArray<string>("a")); //[ 'a', 'a', 'a' ]
console.log(getArray<number>(100)); //[ 100, 100, 100 ]
Genericsに制約を与える
interfaceを利用して必須の型を指定することができる。
interface Result {
a: number;
b: number;
}
class MyData<T extends Result> {
constructor(public value: T) {}
getArray(): T[] {
return [this.value, this.value, this.value];
}
}
内部モジュール
注意:モジュールを別ファイルにするとコンパイルするファイルが複数になるため、コンパイルする時にoutオプションを使い1つのファイルにまとめる。
tsc main.ts --out
// module UserModule { //内部モジュール
// export var name = "taguchi";
// export module AddressModule {
// export var zip = "111-1111";
// }
// }
// 外部モジュールの読み込み↓スラッシュ3つ必須
/// <reference path="./user.ts" />
console.log(UserModule.name);
// console.log(UserModule.AddressModule.zip);
// 呼び出し名が長い時は短くまとめる
// importは外部モジュールを使用する時必須
import addr = UserModule.AddressModule;
console.log(addr.zip);
// モジュールのメンバへのアクセスを可能にするにはexportを使用する
module UserModhule{
export let name = "taguchi";
export module AddressModule{
export let zip = "111-1111";
}
}
モジュール --wikipedia
プログラミングにおいて、一連の機能をひとまとまりになる複数の機能:モジュールに分割し、それぞれ別に開発する場合がある。こうすることで、全体として完成を早めることができる上、モジュール単位でテストしたりすることが可能になり、モジュールの入れ替えで機能を高めたり補修したりすることができるようになる。
プログラムのモジュールは、できるだけ他のモジュールとの結合度を弱めて、独立性を高めることが望ましい。