Make it to make it

いろいろ作ってアウトプットするブログ

TypeScriptハンズオン1(default param, implicit types, union types, interface, enum, class)

デフォルト引数の活用

次のようなファンクションを定義する。

const sayWord = (word: string): string => {
  console.log(word);
  return word;
};

sayWord('hoge');
sayWord(); 

TSでは引数と返り値に対してこのような型指定の形式を取る。

するとVanillaJSのときとは異なり、引数を渡していない型に関してはエラーを引き起こす。

🚨  /Users/sungjoon/Sites/ts-lut/index.ts(7,1)
Expected 1 arguments, but got 0.
    6 | sayWord('hoge');
  > 7 | sayWord();
      | ^^^^^^^^^
    8 | 

そこでどう書くかというと、ES6に則って引数にデフォルトの初期値を渡すことで解決ができる。

const sayWord = (word = 'default'): string => {
  console.log(word);
  return word;
};

sayWord('hoge');
sayWord();

引数に初期値を渡す時点で、TSではその値の型を指定したことと同様な扱いとなる。

ついでにrest parametersでの書き方も交えると、次のように書くことができる。

const sayWord = (word = 'default', ...others: string[]): string => {
  console.log(word);
  return word;
};

sayWord('hoge', 'apple');
sayWord();

Implicit types

上記のように明示的に型を指定しなくても、TSの方で渡した値で型指定をしてくれる。これは変数や引数でも同じ。

let noName = 'Sungjoon';
noName = 1;
🚨  /Users/sungjoon/Sites/ts-lut/index.ts(2,1)
Type '1' is not assignable to type 'string'.
    1 | let noName = 'Sungjoon';
  > 2 | noName = 1;
      | ^^^^^^
    3 | 

変数に一度格納して、それを他の変数に使用としても結果は同じ。

let noName = 'Sungjoon';

let newName = noName;
newName = 1;
🚨  /Users/sungjoon/Sites/ts-lut/index.ts(4,1)
Type '1' is not assignable to type 'string'.
    3 | let newName = noName;
  > 4 | newName = 1;
      | ^^^^^^^
    5 | 

Union types

複数種類の型指定ができるようにするときの指定は次のように書く。

const makeMargin = (x: string | number): string => {
  return `margin: ${x}px`;
};
makeMargin(10);
makeMargin('10');

また、nullとundefinedはデフォルトで振られている値である。

const makeMargin = (x: string | number): string => {
  return `margin: ${x}px`;
};
makeMargin(10);
makeMargin('10');

let dog: string | null = 'Sammy';
// let dog: string | undefined = 'Sammy'; でもOK
// let dog: string = 'Sammy'; でもOK
dog = null;
console.log('dog', dog);
dog = 'Lucie';
dog = undefined;

Interface

Interfaceはオブジェクトの型指定をするときなどに使うことができる。

interface Person {
  name: string;
  age: number;
}

const sayName = ({ name, age }: Person): string => {
  console.log(name);
  return name;
};

sayName({
  name: 'Sungjoon',
  age: 30
});

このとき、返却値にもPerson Interfaceの型指定を与えると、次のように書き換えられる。

interface Person {
  name: string;
  age: number;
}

const sayName = ({ name, age }: Person): Person => {
  console.log(name);
  return { name, age };
};

sayName({
  name: 'Sungjoon',
  age: 30
});

enum

渡す引数が明確なときなどは、 enum を使うようにする。

enum Type {
  Video = 'VIDEO', // (値を代入しなければ)0を返す
  BlogPost = 'BLOG_POST', // (値を代入しなければ)1を返す
  Quiz = 'QUIZ' // (値を代入しなければ)2を返す
}

const createContent = (contentType: Type) => contentType;

console.log(createContent(Type.Quiz));

これでコードをより堅牢にすることができる。

ここで、

console.log(createContent('VIDEO')); // Emits error

などと実行すると、次のようなエラーをはく。

🚨  /Users/sungjoon/Sites/ts-lut/index.ts(10,27)
Argument of type '"VIDEO"' is not assignable to parameter of type 'Type'.
     9 | console.log(createContent(Type.Quiz));
  > 10 | console.log(createContent('VIDEO')); // Emits error
       |                           ^^^^^^^
    11 | 

Class

クラスでも当然ながらTSを使用することができる。

class Team {
  // public:   same as normal usage
  // private:  prevents outside usage
  // readonly: prevents from being changed
  private teamName: string;

  constructor(teamName) {
    this.teamName = teamName;
  }

  score(): string {
    const phrase: string = 'goal!';
    console.log(`${this.teamName} ${phrase}`);
    return `${this.teamName} ${phrase}`;
  }
}

const redWings = new Team('RedWings');
redWings.score();