iT邦幫忙

2023 iThome 鐵人賽

DAY 26
0
自我挑戰組

Rayeee 的 TypeScript 的學習日記系列 第 26

<20230926> Day 26. <TS 專案 10> 來做個小優化吧

  • 分享至 

  • xImage
  •  

昨天我們完成了 Google Maps 的標記功能,今天我們來做個簡單的小小優化吧

今日重點:

  • Use Implements

今天要優化的原因不是因為什麼大問題,而是我們要知道,TypeScript 的本質是幫助我們能快速地處理錯誤,讓我們快速且精準地知道整份程式碼的錯誤在哪裡

今天的優化只是讓我們能夠更好除錯的優化,那就開始吧


我們先來看一下現在的 index.ts

// index.ts
import { User } from "./User";
import { Company } from "./Company";
import { CustomMap } from "./Map";

const map = new CustomMap();
const user = new User();
const company = new Company();
map.addMaker(user);
map.addMaker(company);

看起來很正常,但是其實會有一個小小的隱藏問題,注意這邊對 User 的使用

// User.ts
import { faker } from "@faker-js/faker";

export class User {
  name: string;
  location: {
    lat: number;
    lng: number;
  };
  constructor() {
    this.name = faker.person.firstName();
    this.location = {
      lat: faker.location.latitude(),
      lng: faker.location.longitude(),
    };
  }

  markerContent(): string {
    return `user name: ${this.name}!!`;
  }
}

index.ts 中,map.addMaker() 之所以能接收 user 參數是因為我們在 class MapaddMaker(mappable: Mappable) 中有設定傳入參數必須符合 interface Mappable

// Map.ts
interface Mappable {
  location: {
    lat: number;
    lng: number;
  };
  markerContent(): string;
}

export class CustomMap {
  private googleMap: google.maps.Map;
  constructor() {
    this.googleMap = new google.maps.Map(
      document.getElementById("maps") as HTMLElement,
      {
        zoom: 5,
        center: {
          lat: 23,
          lng: 120.6,
        },
      }
    );
  }
  addMaker(mappable: Mappable): void {    // <== 因為這邊設定參數符合 Mappable
    const markerI = new google.maps.Marker({
      map: this.googleMap,
      position: {
        lat: mappable.location.lat,
        lng: mappable.location.lng,
      },
    });

    markerI.addListener("click", () => {
      // Info Windows DOM
      const contentString = `
          <div>
              <p>地圖</p>
              <p>我是地點 info</p>
          </div>`;
      const infoWindow = new google.maps.InfoWindow({
        content: mappable.markerContent(),
      });
      infoWindow.open(this.googleMap, markerI);
    });
  }
}

而我們的 User 實體有符合 interface Mappable,所以被允許傳入 addMaker() 使用

圖示如下圖:

https://ithelp.ithome.com.tw/upload/images/20230927/20162544yt4VpMQEWw.png

那,如果 User 其實是不符合 interface Mappable 的話呢?
如下圖,理應上 TypeScript 應該要提醒我們知道這個顯而易見的錯誤

https://ithelp.ithome.com.tw/upload/images/20230927/20162544kmyLnd0bMx.png

但是可以發現 index.ts 會有錯誤提示,內容是 class User 不符合 class Map 中設定的 addMarker 要傳入的參數 Type Mappable

https://ithelp.ithome.com.tw/upload/images/20230927/20162544xTl07690xN.png

但是關鍵錯誤的地方 class User 卻沒有報錯

https://ithelp.ithome.com.tw/upload/images/20230927/20162544kUixD0dmcA.png


這就是問題

TypeScript 在 index.ts 中報的錯誤,讓我們知道是 class User 裡面不符合 class Map 中的 Type 設定,我們無法馬上精準地知道問題出在哪邊

這時就是 implements 出馬的時候!

我們可以設計 class User 的時候,就知道他必須要使用 class Map 的方法來標記在地圖上

所以我們在實作 class User 的時候可以預先設定要符合 class Map 裡面的方法

有點饒舌,但是實作意思上就是讓 class User 預先先符合 interface Mappable

先記得把 class Map 的 interface Mappable export 出去

// Map.ts
export interface Mappable {
  location: {
    lat: number;
    lng: number;
  };
  markerContent(): string;
}
...
...

在 class User 中引用,並設定好 User 的 Type 要經由 Mappable 實現 implements

// Map.ts
import { faker } from "@faker-js/faker";
import { Mappable } from "./Map";

export class User implements Mappable {    // this way
  // 如果要給其他模組使用,別忘記要寫 export 出去
  name: string;
  location: {
    lat: number;
    lng: number;
  };
  constructor() {
    this.name = faker.person.firstName();
    this.location = {
      lat: faker.location.latitude(),
      lng: faker.location.longitude(),
    };
  }

  markerContent(): string {
    return `user name: ${this.name}!!`;
  }
}

這樣就完成囉,可以發現,如果我們在實作 class User 裡面的方法時,如果有缺漏,現在 TypeScript 也會正確地在 class User 中報錯,方便我們定位問題囉

https://ithelp.ithome.com.tw/upload/images/20230927/20162544ot80nsknwd.png


上一篇
<20230926> Day 25. <TS 專案 09> 秀出彈窗吧!Showing Popup Windows!
下一篇
<20230928> Day 27. <TS 專案 11> Review 一次吧
系列文
Rayeee 的 TypeScript 的學習日記30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言