ちょっとした技術メモを忘れないうちに書いていく

TypeScript 高度な型

2021-11-16

いまさらながらTypeScriptに入門


型のエイリアス

特定の型に対して名前をつける。

type 型名 = 型定義

//文字列型に別名「s」を指定
type S = string;
const str:S = '文字列';

//タプル型に別名を指定
type Tp = [boolean ,string, number];
const data:Tp = [true, 'AAA', 5];

// オブジェクト型に名前を付ける
type Obj = {name:string, age:number};
const obj:Obj = {
  name:'よしお',
  age:44
}

交差型

複数のオブジェクトの全てのプロパティを持つ型を作成する。

オブジェクト型同士を「&」でつなぐ。

type Person = {
  name:string,
  age:number
}
type Area = {
  area:string
}

// PersonとAreaのプロパティを持つyoshioを作成
const yoshio : Person & Area ={
  name:'よしお',
  age:79,
  area:'TOKYO'
}

共用型 UnionTypes

指定した服須の型のどれかを表す。

「|」で区切って定義する。

//文字列またはnullの型
let str :string|null = 'OK';
str = null;

// 文字列またはnullの配列の定義
let arr:(string|null)[] = ['aa', null , ' bbb'];

// 戻り値が文字列かboolenのメソッド
function test(value:string):string|boolean{
    let result:boolean= true;
    // 何らかの処理
    if(result){
        //処理成功時は文字列を返す
        return 'いいよ?';
    }else{
        //失敗時はfalseを返す
        return false;
    }
}

ReactのReduceでよく見るやつ


// Action型に定義するオブジェクトを指定する、
// typeプロパティ=incrementのオブジェクトか
// typeプロパティ=add、数値型numプロパティのオブジェクト
type Action = {
  type: 'increment';
} | {
  type: 'add';
  num: number;
};

function increaser(state: number, action: Action) {
    //渡されたactionのtypeによって処理を分ける
  switch (action.type) {
    case 'increment':
      return state + 1;
    case 'add':
      return state + action.num;
  }
}

型ガード

型の判定を行い、その型に沿った処理を記述できる。

判定した後は明示的にキャストしなくてもOK。

変数の型を判定し処理を分ける

  • typeof演算子:プリミティブ型の判定
  • instanceof:特定のクラスのインスタンスかどうかの判定
  • in:オブジェクト内に特定のプロパティが存在するかどうか判定

/**
 * 色々な型の引数を受け取るけどそれぞれいい感じに処理する関数
 */
 function func(value:string | number | Test | Object ){

  if(typeof value === 'string'){
    // 文字列型の場合の処理
    return value.substr(0,5);//5文字切り取って返す
  }else if(typeof value === 'number'){
    // 数値型の場合
    return value * 2;//2倍にして返す
  }else if(value instanceof Test){
    // Testクラスのインスタンスの場合の処理
    return `${value.name}さん、こんにちは`;
  }else if("no" in value){
    // noプロパティを持つオブジェクトの処理
    return `No.${value['no']}`
  }else{
    // 当てはまらない場合はundefinedを返す
    return undefined;
  }
}
class Test{
  name:string;
  constructor(){
    this.name = 'テスト';
  }
}
const test = new Test();

console.log(func('aaBBBcc')); // aaBBB
console.log(func(22)); // 44
console.log(func(test)); //  テストさん、こんにちは
console.log(func( {no:5} )); //No.5

ユーザー定義型ガード関数

戻り値にis演算子を指定し、特定の型を判定する関数を定義する。


class Person {
  name:string;
  constructor(){
    this.name = 'よしお';
  }
}

interface Obj{
  name:string;
}

// 引数がPersonのインスタンスかどうか調べる
function isPerson(param:String|Person):param is Person{
  return param instanceof Person;
}
// 引数がObj型かどうか調べる
// ここではnameプロパティを持っていたらObj型とする
function isObj(param:String|Obj):param is Obj{
  return 'name' in param;
}

// Person型かObj型か判定し処理を変える
function func(value:Person|Obj){
  if(isPerson(value)){
    console.log('Person!!');
  }else if(isObj(value)){
    console.log('Obj!!');
  }
}

func(new Person());//Person!!
func({name:'yoshio'});//Obj!!

リテラル型

特定のプリミティブ型のみ代入できる型。

// 文字列のリテラル型
// MON型には文字列JAN、FEB、MARのみ代入できる
type MON = 'JAN'|'FEB'|'MAR';

let str:MON = 'FEB';
//str = '1月';//エラー


// 数値のリテラル型
//numberの定義
type YEAR = 2018|2019|2020|2021|2022;
let y:YEAR = 2018;