TypeScript 學習筆記基礎篇——1小時掌握語法精髓

--悄悄的開始--

1 簡介

TypeScript 是 JavaScript 的類型的超集,可編譯成純 JavaScript。

TypeScript 爲強類型語言,它的類型系統增加了代碼的可維護性。

TypeScript 在編譯階段就可以發現大部分錯誤,比在運行時候發現錯誤更高效。

2 安裝

npm install -g typescript

3 編譯器

VSCode 等主流 IDE 均可。

4 第一個程序

新建文件,後綴爲 firstDemo.ts:

function sayHello (name: string) {
    return 'Hello, ' + name + '!'
}
let myname: string = 'World'
console.log(sayHello(myname))

在控制檯執行命令:tsc firstDemo.ts

編譯生成一個同名的 js 文件:

function sayHello(name) {
    return 'Hello, ' + name + '!';
}
var myname = 'World';
console.log(sayHello(myname));

5 數據類型

① 布爾值 boolean

let flag: boolean = true

② 數值 number

let num1: number= 1000
let num2: number = 0b1010

③ 字符串 string

let str: string= 'Lucy'

④ 空值 void

function execute: void() { 
    // do somthing 
}

⑤ 空值 null undefined

let u: undefined = undefined
let n: null = null

⑥ 任意類型 any

包容任意類型數據:

let o: any = 10
o = 'ten'
console.log(o)
o.desc = 'number'
console.log(o.desc)

注意:定義變量時未指定類型,會被視爲 any 類型。

⑦ 聯合類型 |

let o: string|number = 10
o = 'ten'
console.log(o)

⑧ 接口 interface

interface Fruit { // 類似函數定義,但沒有 ()
    readonly code: string // 只讀屬性
    name: string // 以分號間隔或不寫任何符號,注意別寫成逗號
    count: number
    color?: string // 可選屬性
}
let orange: Fruit = {
    code: 'ORANGE' // 只讀屬性只允許實例化時被賦值一次
    name: '桔子',
   count: 10
}

注意:接口一般首字母大寫;實例屬性多和少都不行,必須一致,可選屬性除外;只讀屬性僅允許在實例化時被初始化一次。

⑨ 數組 [ ]

const arr1: number[] = [1,2,3,4,5,6,7,8,9]
const arr2: Array<number> = [1,2,3,4,5,6,7,8,9] // 利用泛型定義
interface DemoArray {
    [index: number]: number
}
const arr3: DemoArray = [1,2,3,4,5,6,7,8,9] // 利用接口定義,不常用
const arr4: any = [100,'abc',{name:'array'}] // any 類型數組

⑩ 類數組(對象)

類數組對象即爲有 length 屬性和索引的對象,函數內置參數 arguments 就是類數組對象:

// 內置接口
interface IArguments {
    [index: number]: any
    length: number
    callee: Function
}
function test(a: number, b: string, c: boolean) {
    console.log(arguments)
}
test(100, 'xx', true)

6 函數

① 定義方式:

// 定義方式一,約定入參類型及返回值的類型
function test1(a: number, b: number, c: number): number {
    return a + b + c
}
// 定義方式二,約定入參類型及返回值的類型
const test2 = function (a: number, b: number, c: number): number {
    return a + b + c
}
// 定義方式三,約定入參類型及返回值的類型,以及等式左邊變量類型
const test3: (a: number, b: number, c: number) => number = function (a: number, b: number, c: number): number {
    return a + b + c
}
// 定義方式四,以接口形式定義
interface DemoFunc {
    (nameA: string, nameB: string): boolean
}
const test4: DemoFunc = function(nameA: string, nameB: string): boolean {
    return nameA === nameB
}

② 入參:

// 參數默認值、可選參數
function test1(a: number, b: number = 2, c?: number): number { // b 指定默認值,c 爲可選參數,可選參數必須放在後面 
    return a + b + (c||0)
}
// 剩餘參數
function test2(a, b, ...params) {
    // 略,參考 ES6 語法
    console.log(params)
}
test2(1,2,3,4,5,6)

③ 重載:

// 重載
function switchType(x: number): string
function switchType(x: string): number
function switchType(x: number | string): number | string {
    if (typeof x === 'string') {
        return Number(x)
    } else if (typeof x === 'number') {
        return x + ''
    }
}
// 前面是函數定義,最後是函數實現,TypeScript 會優先從最前面的函數定義開始匹配,所以應當先寫精確的定義

7 斷言類型

關鍵字 as

① 遇到聯合類型的時候,可以將其斷言爲其中一個類型。舉例如下:

interface Triangle { // 接口
    sideLength: number
}
interface Circle { // 接口 
    radius: number
}

function getData(shape: Triangle | Circle) {
    // return shape.sideLength // 編譯報錯
    // return shape.radius // 編譯報錯
    return (shape as Triangle).sideLength || (shape as Circle).radius  // 斷言爲子類型
}
const tri: Triangle = {
    sideLength: 100
}
console.log(getData(tri))

② 將一個父類斷言爲更加具體的子類。舉例如下:

class Shape {} // 父類
class Triangle extends Shape { // 子類
    sideLength: number
}
class Circle extends Shape { // 子類
    radius: number
}

function getData(shape: Shape) { // 將父類指定爲子類
    // return shape.sideLength // 編譯報錯
    // return shape.radius // 編譯報錯
    return (shape as Circle).radius || (shape as Triangle).sideLength // 斷言爲子類型
}
const tri: Triangle = {
    sideLength: 200
}
console.log(getData(tri))

③ 用法小結:

可以將任何類型斷言爲 any,any 也可以被斷言爲任何類型;要將 A 斷言爲 B,只需 A 兼容 B 或 B 兼容 A 即可。

8 聲明文件

全局聲明寫在以 .d.ts 爲後綴的類型聲明文件裏

① 聲明全局變量 declare var | declare let | declare const

declare const BASE: string // 僅聲明類型,不能定義具體值

② 聲明第三方文件

declare let jQuery: (selector: string) => any // 僅定義類型,不能定義具體實現

注意:也可以直接下載第三方文件,直接下載則無需聲明爲全局變量:npm install @types/jquery --save-dev

③ 聲明全局方法 declare function

declare function func(str: string): void // 僅定義方法類型,不能定義具體實現,支持方法重載

④ 聲明全局類 declare class

declare class Person {
    name: string // 靜態變量
    constructor(name: string)  // 構造函數
    getName(): string // 靜態方法,不要定義具體實現
}

⑤ 聲明全局枚舉(外部枚舉) declare enum

declare enum Weekdays { mon, tues, wen, thur, fri, sat, sun } // 僅定義類型,不能定義具體值

注意:namespace 關鍵字屬於 TypeScript 早期關鍵字,爲了避免全局變量污染而創建的,隨着 ES6 的出現,module 關鍵字基本上代替了 namespace 的使用。

9 元祖(Tuple)

元祖類似於數組,但存儲的數據類型可以是不同的。

const scores:[string, number] = ['Good', 100]
console.log(scores[0])
scores.push('Excellent')
console.log(scores);
scores.pop()
console.log(scores)

10 枚舉(Enum)

定義一些帶名字的常量使用枚舉可以清晰地表達意圖或創建一組有區別的用例,TypeScript 支持數字的和基於字符串的枚舉。

enum Colors { Yellow, Green, Orange, Blue } // 注意,定義不用等號,值不用寫引號
console.log(Colors[0]) // 枚舉成員會被賦值爲從 0 開始遞增的數字
console.log(Colors['Yellow']) // 同時也會對枚舉值到枚舉名進行反向映射
enum Days {Sun = 7, Mon = 1, Tue, Wed, Thu, Fri, Sat} // 也可以在定義時手動賦值
console.log(Days)

11 類 (Class)

① Typescript 裏的類和 Java 類似,可以使用修飾符 publicprivate 和 protected 修飾類裏面定義的屬性、構造函數和方法,使用 class 關鍵字。

public 修飾的屬性或方法是公有的,可以在外部訪問,默認值;

private 修飾的屬性或方法是私有的,不能在外部訪問;

protected 修飾的屬性或方法和 private 類似,區別在於它在子類中可以被訪問。

class Student {
    public name: string // 外部可直接訪問
    protected studentNo: string // 外部不可直接訪問,子類可訪問
    private score: number // 外部和子類均不可直接訪問
    public constructor(studentNo: string, name: string) {
        this.studentNo = studentNo
        this.name = name
    }
    public getName() {
        return this.name
    }
    public setName(name: string) {
        return this.name = name
    }
    public setScore(score: number) {
        return this.score = score
    }
    public getScore() {
        return this.score
    }
}
const jim = new Student('001','Jim')
jim.setScore(100)
console.log(jim.name) // 可以直接訪問 public 修飾的屬性
console.log(jim.getName())
// console.log(Jim.studentNo) // 不能訪問 protected 修飾的屬性,編譯報錯
// console.log(Jim.score) // 不能訪問 private 修飾的屬性,編譯報錯
console.log(jim.getScore()) // 可以通過公有方法訪問 private 或 protected 修飾的屬性

class StarStudent extends Student { // 創建子類
    public constructor(studentNo: string, name: string) {
        super(studentNo, name)
        console.log(this.studentNo) // 可以訪問父類 protected 修飾的屬性或方法
        // console.log(this.score) // 不能訪問父類 private 修飾的屬性或方法,編譯報錯
    }
}

const lee = new StarStudent('002', 'Lee')
console.log(lee.getName())

② 定義類時,還可以直接在構造函數中定義屬性。例如:

// 以下兩種類的定義方式效果一致
class Boy {
    public name: string
    public constructor(name: string) {
        this.name = name
    }
}
class Girl {
    public constructor(public name:string) {}
}

只讀屬性 readonly

被 readonly 修飾的屬性,只能讀,不能改。

class Person {
  // public readonly name
  public constructor(public readonly name) {
    // this.name = name
  }
}
let alex = new Person('Alex')
console.log(alex.name) // Alex
// alex.name = 'Alex Zhang' // 編譯報錯

④ 抽象類 abstract

抽象類不允許被實例化,抽象類中定義的抽象方法必須被子類實現。

abstract class Person {
    name: string
    public abstract saySomething() // 需要加 abstract 修飾符,否則編譯報錯
}
// const william = new Person() // 抽象類不能被實例化,編譯報錯
class Teacher extends Person {
    public saySomething () {
        console.log('Good Morning, class!') // 抽象方法必須被實現,否則編譯報錯
    }
}

--End(未完待續)--

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章