Typescript・Javascript便利なコード



# InstanceOf (Javascript)

``` typescript

class TwTweet {
    twId: number;
}

class FbPost {
    fbId: number;
}

function analyzePost(post: TwTweet | FbPost) {
    if(post instanceof TwTweet){
        // TwTweet
        console.log(post.twId)  // 型安全になる
        return
    }

    if(post instanceof FbPost){
        // FbPost
        console.log(post.fbId)  // 型安全になる
        return
    }
}

```

- 注意

``` typescript

interface TwTweet {
    twId: number;
}

interface FbPost {
    fbId: number;
}

function analyzePost(post: TwTweet | FbPost) {
    // 効かない
    if(post instanceof TwTweet){
        console.log(post.twId)
        return
    }

    // 効かない
    if(post instanceof FbPost){
        console.log(post.fbId)
        return
    }

    //
    console.log("ここになる")
}

```
---

# TypeOf (Javascript)
- 外部のレスポンスを型にする方法
- 簡単・ツールなどは型安全できます。

``` typescript


// https://developer.twitter.com/en/docs/twitter-ads-api/creatives/api-reference/video-website
const sampleVideoWebsiteCard = {
  videoPosterHeight: '9',
  name: 'video website card',
  websiteShortenedUrl: 'https://t.co/zadeUSVD18',
  videoHeight: '9',
  mediaUrl: 'https://video.twimg.com/amplify_video/vmap/958224897255211013.vmap',
  contentDurationSeconds: '8',
  videoOwnerId: '756201191646691328',
  mediaKey: '13_958224897255211013',
  websiteDisplayUrl: 'developer.twitter.com',
  id: '5a4vf',
  videoWidth: '16',
  websiteDestUrl: 'https://developer.twitter.com',
  createdAt: '2018-01-30T06:30:01Z',
  cardUri: 'card://958225772740714496',
  title: 'Twitter Developers',
  websiteUrl: 'https://developer.twitter.com',
  updatedAt: '2018-01-30T06:30:01Z',
  posterMediaUrl: 'https://pbs.twimg.com/amplify_video_thumb/958224897255211013/img/EnyDab6vErGm4Avd.jpg',
  videoPosterWidth: '16',
  deleted: false,
  cardType: 'VIDEO_WEBSITE',
  cardKbn: kbnConstants.TW_ADS_CARD_KBN.VIDEO_WEBSITE,
}
export type VideoWebsiteCardJson = typeof sampleVideoWebsiteCard

function analyzePost(post: VideoWebsiteCardJson) {
    console.log(post.websiteDisplayUrl) // 型安全になる
}

```
---

# Partial (Typescript)
- レスポンスは信頼がなければ、Partialをよく使います。
- APIサーバーにデータを一部登録するときに、Partialを使います。


``` typescript


// https://developer.twitter.com/en/docs/twitter-ads-api/creatives/api-reference/video-website
const sampleVideoWebsiteCard = {
  videoPosterHeight: '9',
  name: 'video website card',
  websiteShortenedUrl: 'https://t.co/zadeUSVD18',
  videoHeight: '9'
}
export type VideoWebsiteCardJson = typeof sampleVideoWebsiteCard

function analyzePost(post: Partial<VideoWebsiteCardJson>) {
    console.log(post.name); // undefined可能性があります
}

```

---

# Proxy (Javascript)
- テストのMockのためよく使う方法です。

``` typescript

import axios, { AxiosInstance } from 'axios';

export class Api {
  private readonly axios: AxiosInstance;

  constructor() {
    this.axios = axios.create({
      headers: {
        'Content-Type': 'application/json',
      },
    });
  }

  async getMe() {
    const response =  await this.axios
      .request<{name: string}>({
      method: 'get',
      url: '/v1/me',
    });

    return response.data;
  }
}

export const clientApi = new Api();

clientApi.getMe();


// eslint-disable-next-line object-curly-newline
export function makeMock<T extends Api>(name: string, target: Partial<T> = {}): T {
  return new Proxy(
    target,
    {
      get: function(target: T, handler: string, receiver: unknown) {
        if (Object.keys(target).indexOf(handler) === -1) {
          return () => {
            throw new Error(`${name}.${handler}(...)　has not defined`);
          };
        }

        return Reflect.get(target as unknown as Record<string, unknown>, handler, receiver);
      },
    },
  ) as T;
}

const mockClientApi = makeMock<Api>('api', {
  getMe: async () => {
    return  { name: 'Mock User' };
  },

});

export function useApi() {
  if (process.env.MODE === 'test') {
    return mockClientApi;
  } else {
    return clientApi;
  }
}

useApi().getMe();


```
---

# 以上です。

ありがとうございました。