LoginSignup
0
2

More than 1 year has passed since last update.

TypeScriptチートシート4(応用)

Last updated at Posted at 2022-01-08

インターセクション型

・合併型(uniontypes):AかBどちらかの型を持つ
どちらかの型が成立すればOK

・交差型(intersection):AとB両方の型を持つ(共通する型ではない)
両方の型を満たせばOK

type Engineer = {
  name: string;
  role: string;
};

type Blogger = {
  name: string;
  follower: number;
};

type EandB = Engineer & Blogger;
const suda: EandB = {
  name: "masaki",
  role: "front-end",
  follower: 10000,
};

Union 型の絞り込み

interface Hoge {
  foo: string;
  bar: number;
}
interface Piyo {
  foo: number;
  baz: boolean;
}

type HogePiyo = Hoge | Piyo;

//オブジェクトにbarとbaz両方あるとどちらの型になるのかわからないので、参照できない

const obj: HogePiyo = {
  foo: 'hello',
  bar: 0,
  baz:false
};

//プロパティ 'bar' は型 'HogePiyo' に存在しません。
//プロパティ 'bar' は型 'Piyo' に存在しません。
const aaa = obj.bar

in

'bar' in objというのはbarというプロパティがobjに存在するならtrueを返し、そうでないならfalseを返す式
型を絞り込めば、正しく使える


function useHogePiyo(obj: Hoge | Piyo): void {
  // ここではobjはHoge | Piyo型
  if ('bar' in obj) {
    // barプロパティがあるのはHoge型なのでここではobjはHoge型
    console.log('Hoge', obj.bar);
  } else {
    // barプロパティがないのでここではobjはPiyo型
    console.log('Piyo', obj.baz);
  }
}

Type guard

typeof演算子は与えられた値の型を文字列で返す演算子


function func(value: string | number): number {
  if ('string' === typeof value) {
    // valueはstring型なのでlengthプロパティを見ることができる
    return value.length;
  } else {
    // valueはnumber型
    return value;
  }
}

instanceof

class Dog {
  speak() {
    console.log("bow-bow");
  }
}

class Bird {
  speak() {
    console.log("tweet-tweet");
  }

  fly() {
    console.log("flutter");
  }
}

type Pet = Dog | Bird;
function havePet(pet: Pet) {
  pet.speak();
  if (pet instanceof Bird) {
    pet.fly();
  }
}

havePet(new Bird());

//コンソール
tweet-tweet
flutter

havePet(new Dog());

//コンソール
bow-bow

タグ付きユニオン

オブジェクトに対してユニオン型を使うときに役立つ

//type: 'Some'
//type: 'None'
//というタグをつけておく
//このタグを使って、型を分ける

interface Some<T> {
  type: 'Some';
  value: T;
}
interface None {
  type: 'None';
}

type Option<T> = Some<T> | None;

//ifまたはswitchで場合分け

function map<T, U>(obj: Option<T>, f: (obj: T)=> U): Option<U> {
  if (obj.type === 'Some') {
    // ここではobjはSome<T>型
    return {
      type: 'Some',
      value: f(obj.value),
    };
  } else {
    return {
      type: 'None',
    };
  }
}

//上と下は同じ

function map<T, U>(obj: Option<T>, f: (obj: T)=> U): Option<U> {
  switch (obj.type) {
    case 'Some':
      return {
        type: 'Some',
        value: f(obj.value),
      };
    case 'None':
      return {
        type: 'None',
      };
  }
}

ユニオン型とインターセクション型を合わせて使ってみる

interface Hoge {
    type: 'hoge';
    foo: string;
}
interface Piyo {
    type: 'piyo';
    bar: number;
}
interface Fuga {
    baz: boolean;
}

type Obj = (Hoge | Piyo) & Fuga;

function func(obj: Obj) {
    // objはFugaなのでbazを参照可能
    console.log(obj.baz);
    if (obj.type === 'hoge') {
        // ここではobjは Hoge & Fuga
        console.log(obj.foo);
    } else {
        // ここではobjはPiyo & Fuga
        console.log(obj.bar);
    }
}

型アサーション

手動で型を上書きする
as

//今の状態の型
//const input: HTMLElement | null
const input = document.getElementById('input')
//input.valueなど使えない

const input = <HTMLInputElement>document.getElementById('input')
//または
const input = document.getElementById('input') as HTMLInputElement
input.value = 'value'

!

nullじゃないと言い切る方法
if文で条件分岐しなくてもよくなる

//今の状態の型
//const input: HTMLElement
const input = document.getElementById('input')!

インデックスシグニチャ

・オブジェクトが複数のプロパティを持つ可能性を示す
・[key:T]:U のように示す
・keyはstringかnumberのみ

const capitals: {
    [countryName:string]:string
} = {
    japan: 'tokyo',
    korea: 'soul',
    //エラー
    age:23
}

関数のオーバーロード

戻り値の型を正しく伝える

function toUpperCase(x: string | number): string | number {
  if (typeof x === "string") {
    return x.toUpperCase();
  }
  return x;
}

const upperHello = toUpperCase("hello")
//upperHelloの型は、const upperHello: string | number
//---------------------------------------------------

function toUpperCase(x: string ): string
function toUpperCase(x: number): number
function toUpperCase(x: string | number): string | number {
  if (typeof x === "string") {
    return x.toUpperCase();
  }
  return x;
}

//オーバーロードすることによって関数の戻り値の型を正しくできる
const upperHello = toUpperCase("hello")


Optional Chaining

プロパティが連結していくとき指定したプロパティがなければnullを返す

//?はあってもなくてもいいプロパティ
interface DownLoadedData {
    id: number;
    user?: {
        name?: {
            first: string;
            last: string
        }
    }
}

const downloadedData: DownLoadedData = {
    id:1
}

//エラー
//オブジェクトは 'undefined' である可能性があります
console.log(downloadedData.user.name)

//解決策の一つ
//userがあったらnameを返す
//なければundefinedを返す
console.log(downloadedData.user?.name)

Nullish Coalescing

userがundefined or nullの場合??の後ろを返す

const userData = downloadedData.user ?? 'no-user'

LookUp型

オブジェクトの型のメンバが持っている型にアクセスする

interface DownLoadedData {
  id: number;
  user: {
    name?: {
      first: string;
      last: string;
    };
  };
}

type id_1 = DownLoadedData['id']
//number
type id_2 = DownLoadedData['user']['name']
//type id_2 = {
//    first: string;
//    last: string;
//} | undefined

具体例

第一引数Tは{ foo: string; bar: number; }型
第二引数K extends keyof Tはfooまたはbarに限定する
戻り値T[K]は({ foo: string; bar: number; })['foo']型つまりstring

function pick<T, K extends keyof T>(obj: T, key: K): T[K] {
  return obj[key];
}

const obj = {
  foo: 'string',
  bar: 123,
};

const str: string = pick(obj, 'foo');
const num: number = pick(obj, 'bar');
// エラー: Argument of type '"baz"' is not assignable to parameter of type '"foo" | "bar"'.
pick(obj, 'baz');

constアサーション

as const をつけると変えられなくなる

let milk = 'milk' as const
//let milk: "milk"

const array = [10,20]
//const array: number[]

const array = [10,20] as const
//const array = [10,20] as const



0
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
2