從 JavaScript 到 TypeScript 2 - 基礎特性和類型推導

隨着應用的龐大,項目中 JavaScript 的代碼也會愈來愈臃腫,這時候許多 JavaScript 的語言弊端就會愈發明顯,而 TypeScript 的出現,就是着力於解決 JavaScript 語言天生的弱勢:靜態類型。html

前端開發 QQ 羣:377786580前端

這篇文章首發於個人我的博客 《據說》,系列目錄:vue

在上一篇文章 《從 JavaScript 到 TypeScript 1 - 什麼是 TypeScript》 中咱們討論了什麼是 TypeScript。這一篇文章咱們來介紹 TypeScript 一些基礎類型約束。node

基礎類型

咱們先簡單的聲明一些變量:typescript

let a: number
let b = true  // 有默認值的狀況,甚至不須要聲明類型,ts 會自動推導
let c: [string, number] // 元組
enum Color {Red, Green, Blue} // 枚舉
let d: { name: string } = { name: 'linkFly' }

當咱們給這些變量賦錯誤的類型值的時候,會拋出類型錯誤異常。express

clipboard.png

是否是很簡單,TypeScript 優秀的設計使得即便你沒有接觸過它,可是仍然可以讀懂它。數組

複雜類型

// array
let list_a: number[] = [1, 2, 3]
let list_b: Array<number> = [1, 2, 3] // number 類型的數組
let list_c: [string, number] = ['linkFly', 0]

// any
let notSure: any = 4
notSure = true // any 類型能夠自由賦值

// 函數類型
let fn: (id: string) => number = (id) => 1
// 這裏使用了 ECMAScript 6 的箭頭函數,和下面的代碼等價
let fn: (id: string) => number = function (id) {
  return 1
}

clipboard.png

高級類型

// 聯合類型, foo 是 string 或 number
let foo: string | number = 1

// 類型斷言,強制使用兼容類型中的某一類型
(foo as string)

// 類型保護(判斷)
if (typeof foo === 'string') {
  // dosomething
}
// 類型保護(判斷)
if (foo instanceof String) {
  // dosomething
}

clipboard.png

Model

從前幾年熱門的 MVC 一直到如今熱門的 MVVM,咱們發現不管是 MVC(Model-View-Controller) 仍是 MVVM(Model-View-ViewModel),咱們始終拋不開一個關鍵的地方 —— 數據層:Model架構

由於本質上整個頁面的操做都是在進行數據流動,頁面展示本質上都是數據,而咱們經過 Model 來描述數據。ide

這是一個簡單的 Model 演示:函數

let user : { id: number, name: string } = { id: 1, name: 'linkFly' }

在 TypeScript (或者是全部強 OO 語言)中,推薦以 Model 來描述數據的方式也就是 Class

這一小節只簡單介紹 Class 和 泛型,實際項目中可能還會牽扯更多更強大的 OO 概念:接口、抽象類、繼承類、繼承屬性。

這些知識不是一蹴而就的,而是須要在項目中不斷探索不斷組合的。

Class 類

全部類型的根本都是類,TS 中聲明一個類的語法很是簡單,可讀性很高。

注意,TS 中類型是核心,當你想把一個項目從 JavaScript 遷移到 TypeScript 的時候,須要爲項目中補充大量的類型,而這些類型大部分都是基於 Class 構建的。

這是一個簡單的類:

class User {
  id: number
  name: string
}

let user: User = { id: 1, name: 'linkFly' }

固然隨着需求的不一樣,也能夠補充不少細節:

class User {
  // 只讀屬性
  readonly id: number

  // 存取器, get/set
  private _name: string
  get name(): string {
    // dosomething 
    return this._name
  }
  set name (name: string) {
    console.log('this is set method')
    // dosomething
    this._name = name
  }

  // 構造函數
  constructor (id: number, theName: string) {
      // 只讀屬性只能在構造函數裏初始化
      this.id = id
      this._name = theName
  }

  // 實例方法
  say () {
    console.log(`name: ${this.name}`)
  }

  // 靜態方法(類方法)
  static print () {
    console.log('static method')
  }
}

let user = new User(1, 'linkFly')
user.name = 'tasaid' // 會輸出 'this is set method'
user.say() // 實例方法
User.print() // 靜態方法

clipboard.png

泛型

泛型是用來解決類型重用的問題。

例以下面一個函數,只能傳遞 number 的參數並返回:

function identity(arg: number): number {
    // dosomething
    return arg
}

如今想傳遞一個 string 類型的參數,而後也返回它,這個時候就可使用泛型,使用泛型能夠接收任意類型並返回:

// 這個 T 就是泛型,也能夠叫其餘名字
function identity<T>(arg: T): T {
    // dosomething
    return arg
}

identity<string>('linkfly')
identity('linkfly') // 自動推導
identity(0)
identity(true)

咱們能夠輕鬆的使用泛型來實現數據包裝:

function fetch<T>(url: string): Promise<T> {
  // 遠程請求數據並返回結果
  return fetch(url).then(data => {
    return data as T
  })
}

class User {
  name: string
}

// 泛型使用
let user = fetch<User>('https://tasaid.com/user')

小 tis

  • TypeScript 中文網 能夠看到完整 TS 特性。
  • 在項目初期使用 TS 中,會須要很大的時間和精力,去編寫和架構基本業務類型(Models),在此以後會愈來愈方便快捷。
  • 一些沒有行爲只須要作類型檢查的類型(沒有方法的 Models),可使用 TypeScript 聲明文件 (*.d.ts),例如:
declare namespace Models {
  interface GPS {
    lat: number
    lng: number
  }
}

這個系列的文章不會講解 TypeScript 的聲明文件,可是它是 TypeScript 中不可缺乏的一部分。

  • 儘可能減小使用 any 類型,它意味着類型不可控
  • 某些變量或者第三方庫中屬性沒法感知,使用 as 強制進行類型推導便可。
window.tempName = 'linkFly' 
// Errors: [ts] Property 'tempName' does not exist on type 'Window'.

// 強制推導
(window as any).tempName = 'linkFly'

至此,咱們對 TypeScript 類型、Model 已經有了必定的瞭解,在下一篇,咱們將瞭解如何引入和編譯 TypeScript:《從 JavaScript 到 TypeScript 3 - 引入和編譯

 

TypeScript 中文網:https://tslang.cn/

TypeScript 視頻教程:《TypeScript 精通指南

相關文章
相關標籤/搜索