1. 程式人生 > >「譯」深入typescript系列1

「譯」深入typescript系列1

為什麼要用typescript

這裡列舉了兩個主要的目的

  • typescript為js提供了可選的型別系統(type system)
  • typescript為當前的js引擎提供了未來JS版本才能使用的特性

typescript的型別系統

你獲取想知道為什麼要給javascript新增型別系統呢?

型別系統已經被證明是一種可以增強程式碼質量和可讀性的能力,大型團隊(例如谷歌,微軟,facebook)都在印證著這個結論,更具體點說:

  • 當要進行程式碼重構時,型別系統能給予更高的靈活度,因為在編譯時進行異常捕獲要好於在執行時
  • 型別系統是最好的文件格式之一,函式簽名(function signature)是一個定理,而函式體則是相應的證明(proof)

typescript會盡量保持一個低門檻,來保證開發者可以低成本的學習編寫ts程式碼

你的js程式碼就是ts程式碼

typescript為js提供了編譯時的型別檢查,最棒的是型別完全是可選的,你的js程式碼(.js檔案)可以重新命名成(.ts)檔案,typescript同樣會返回和原有js檔案一樣的輸出。通過可選的型別檢查,typescript就是嚴格的js超集。

型別可以是隱式的

在程式碼開發階段,typescript會盡可能用比較低的成本去推斷儘可能多的型別資訊,例如,在接下來的例子中,typescript將會知道foo是number型別,當在第二行程式碼中又給foo賦值為一個字串型別的值時,就會報出錯誤

  var foo = 123;
  foo = '456'; // Error: cannot assign `string` to `number`
複製程式碼

example

這種型別推斷具有良好的動機,如果你也有像上述例子相似的場景,在接下來的程式碼中,並不確定foo到底是number型別還是string型別,這樣的問題在大型的多檔案程式碼庫中經常能碰到,我們稍後會繼續深入瞭解型別推斷的規則。

型別可以是顯式的

根據我們在之前提到的,typescript將會盡能安全的進行型別的推斷,然而,也可以使用註解去明確達到下面兩個目的

  • 有助於編譯器進行友好的提示,還有就是對於那些不得不閱讀你程式碼的開發者,文件的填充也是非常重要的
  • 強制讓在編譯器上看到的提示就是你希望讓使用者(閱讀你程式碼的開發者)看到的提示,也就是說,你對於程式碼的理解匹配了程式碼的演算法分析(這一步通過編譯器來完成)

typescript是用尾隨式的型別註解

  var foo: number = 123;
複製程式碼

下面這個例子編譯器將會丟擲一個error

  var foo: number = '123'; // Error: cannot assign a `string` to a `number`
複製程式碼

我們會在後續章節討論註解語法的細節

typescript是結構化的

在typescript中,我們想讓js開發者以更小的學習成本來編寫ts程式碼,所以型別都是結構化的,這意味著,”鴨子型別“是一種類(class)語言優先的結構,考慮下面這個例子,函式iTakePoint2D將會接收任何包含了x和y的物件作為引數

  interface Point2D {
    x: number;
    y: number;
  }
  interface Point3D {
      x: number;
      y: number;
      z: number;
  }
  var point2D: Point2D = { x: 0, y: 10 }
  var point3D: Point3D = { x: 0, y: 10, z: 20 }
  function iTakePoint2D(point: Point2D) { /* do something */ }

  iTakePoint2D(point2D); // exact match okay
  iTakePoint2D(point3D); // extra information okay
  iTakePoint2D({ x: 0 }); // Error: missing information `y`
複製程式碼

型別錯誤不會阻止js程式碼的執行

為了使js程式碼遷移到ts程式碼更為簡單,即使是有編譯錯誤,預設的,typescript也會觸發有效的js程式碼使其正常執行

  var foo = 123;
  foo = '456'; // Error: cannot assign a `string` to a `number`
複製程式碼

等價於觸發下面這段js程式碼

  var foo = 123;
  foo = '456';
複製程式碼

所以從js程式碼過渡到ts程式碼可以採用逐漸更新升級的策略,這也是ts不同於其他語言編譯器工作以及遷移到ts的原因

型別可以是調節粒度的

typescript的一個主要的設計目標就是可以在typescript儘可能簡單和安全的使用已經存在的js庫,typescript通過宣告(declaration)來達到這個目的,typescript提供了一個可變的比例針對你想在宣告檔案中放置多少宣告資訊,宣告的越具體,型別檢測和程式碼提示就越詳細,注意,針對大多數流行的js庫已經有寫好的宣告檔案[github.com/borisyankov…](DefinitelyTyped community), 所以針對大多數的目的:

  • 宣告檔案已經存在
  • 或者至少,已經有大量的經過了review的宣告模版可用了

為了快速定義一個自己的宣告檔案,以jQuery為例,預設的,在你使用一個變數之前,typescript都期望你首先要宣告它

  $('.awesome').show(); // Error: cannot find name `$`
複製程式碼

為了快速解決這個問題,你可以告訴typescript,這裡確實有一個叫做$的傢伙

  declare var $: any;
  $('.awesome').show(); // Okay!
複製程式碼

如果你想基於這個基礎的定義來提供更多的資訊以防止出現編譯error,可以這樣做

  declare var $: {
    (selector:string): any;
  };
  $('.awesome').show(); // Okay!
  $(123).show(); // Error: selector needs to be a string
複製程式碼

現在就能使用js的新特性

typescript提供了很多新特性針對當前的js引擎,typescript團隊也在積極的新增這些特性,這份特性列表也會隨著時間變得越來越豐富,這裡以一個class為例。

  class Point {
      constructor(public x: number, public y: number) {

      }
      add(point: Point) {
        return new Point(this.x + point.x, this.y + point.y);
      }
  }

  var p1 = new Point(0, 10);
  var p2 = new Point(10, 20);
  var p3 = p1.add(p2); // { x: 10, y: 30 }
複製程式碼