TypeScript入門指南(基礎篇)

文章首發於:github.com/USTB-musion…python

寫在前面

ts是擁有類型系統的js的超集,近年來很是火熱。能夠這麼說,ts纔是真正意義上的js。雖然ts的官方文檔很是全面,可是對於原來沒有接觸過ts的同窗來講,全篇通讀下來須要耗掉很多時間,這篇文章旨在爲嘗試入門ts的同窗使用。react

本文將從如下幾部分進行總結:c++

  1. TypeScript的優點
  2. 強類型與弱類型的區別
  3. 動態類型與靜態類型的區別
  4. 基礎類型
  5. 接口類型
  6. 函數
  7. 泛型

TypeScript的優點

1.幫助更好地重構代碼

一個好的代碼習慣是經常對本身寫的代碼進行小的重構,使得代碼可維護性更強。可是對於不少線上運行的代碼,代碼測試覆蓋率每每不是很高,有時候哪怕一個變量名的改動,都會牽一髮而動全身。而對於使用ts編寫的項目就不會有這種擔憂。ts的靜態檢查特性會幫助找出代碼中有錯誤的部分。git

2.vscode等IDE的提示更加智能

js是一門動態弱類型解釋語言,變量聲明後能夠改變類型,並且類型須要在運行時才能肯定。而ts的報錯提示是在編譯時,不是在運行時。因此使用ts帶來的靜態類型檢查等特性將使得IDE的提示更加完善。github

3.類型聲明自己就是很是好的文檔

當你接手一個有歷史包袱的項目時,確定會頭疼於文檔和代碼註釋的缺失,而對於ts來講,是能夠作到代碼即文檔的,經過聲明文件能夠知道哪些字段的含義以及哪些字段是必填和選填的。舉個簡單例子,當封裝一個button的組件時:數組

export interface ButtonProps {
  style?: React.CSSProperties
  className?: string
  label?: React.ReactNode
  type?: 'primary' | 'default' | 'search'
  size?: 'sm' | 'md' | 'lg' | 'mini'
  disabled?: boolean
  title?: string
  onClick?: ((e: React.MouseEvent<HTMLButtonElement>) => void)
}
複製代碼

經過這些聲明文件能夠知道,當使用這個button文件時,style是一個可選值,表示一個能夠自定義樣式的style字段。type也是一個可選值,表示按鈕的顏色類型,能夠選擇'primary','default','mini'其中的一種。disabled也是一個可選值,傳入的值必須是boolean類型。因此就能夠看出類型聲明自己就是很是好的文檔。bash

強類型與弱類型的區別

強類型語言: 強類型語言不容許改變變量的數據類型,除非進行強制類型轉換。函數

例如:若是定義了一個字符串變量str,若是沒有進行強制類型轉換,是把str不能看成布爾值,整型等非字符型進行處理的。c,c++,Java等都是強類型語言。性能

弱類型語言: 定義與強類型語言相反,一個變量能夠被賦予不一樣數據類型的值。測試

var a = '111';
var b = 222;
a = b;
console.log(a) // 222
複製代碼

如以上的js代碼所示,a是一個字符串變量,b是一個整型變量,可是卻能夠把b賦值給a,把a打印出來的值是222。

強類型的嚴謹性能有效地避免不少錯誤。

動態類型與靜態類型的區別

動態類型語言: 在執行階段才作類型檢查。

例如:js/python等就是屬於動態類型語言,對類型檢查很是寬鬆,bug可能隱藏好久才被發現。

靜態類型語言: 在編譯階段就作類型檢查

例如: c++/Java等屬於靜態類型語言,對類型檢查很是嚴格,bug在編譯階段就會被發現。能作到代碼即文檔。

基礎類型

ES6的類型能夠分爲Boolean,Number,String,Array,Function,Object,Symbol,undefined,null。而TypeScript的數據類型則在ES6的基礎上加上void,any,never,元組,枚舉,高級類型。

基本語法

: type

TypeScript的基本類型語法是在變量以後使用冒號進行類型標識,這種語法也揭示了TypeScript的類型聲明其實是可選的。

boolean

boolean是最基礎的數據類型,在ts中,使用boolean來定義布爾值

let isDone: boolean = false;
複製代碼

number

在ts中,使用number來定義數值類型

let num: number = 123

複製代碼

string

在ts中,使用string來定義字符串類型

let name: string = 'jarod'
複製代碼

array

在ts中,定義數組方式有兩種: 一種是在能夠在元素類型後面接上[],表示由此元素組成的一個數組:

let arr1: number[] = [1, 2, 3]
複製代碼

還有一種是使用數組泛型,Array<元素類型> :

let arr2: Array<number> = [1, 2, 3]

複製代碼

元組

若是想在數組內表示不一樣元素怎麼辦?這時候就須要使用元組類型了。元組類型容許表示一個已知元素數量和類型的數組,各元素的類型沒必要相同。 好比,你能夠定義一對值分別爲number和string類型的元組。

let hello: [number, string] = [0, 'hello']
複製代碼

枚舉

enum類型是對JavaScript標準數據類型的一個補充。 像C#等其它語言同樣,使用枚舉類型能夠爲一組數值賦予友好的名字。

enum Month {
    Jan,
    Feb,
    Mar
}
let month = [Month.Jan, Month.Feb, Month.Mar]
複製代碼

never

若是一個函數永遠沒有返回值時,咱們能夠聲明其爲void類型:

function example(): never {
    throw new Error('never');
}
複製代碼

any

any是ts的一個特殊類型,一旦聲明爲any,則意味着關閉來ts的類型檢查,

let x: any = 0;
x = [];
x = false; 
x = '';
複製代碼

對於any類型的變量,能夠賦予任何類型的值。使用any對遷移js的項目是很友好的。可是在真正開發中,儘可能仍是少用any爲好。

void

在ts中,void表示函數沒有返回值。

function example(): void {
    console.log('this is void type');
}
複製代碼

undefined和null

在TypeScript裏,undefined和null二者各自有本身的類型分別叫作undefined和null。 和 void類似,它們的自己的類型用處不是很大:

let u: undefined = undefined;
let n: null = null;
複製代碼

readonly

一些對象屬性只能在對象剛剛建立的時候修改其值。 你能夠在屬性名前用 readonly來指定只讀屬性,在結合react使用的過程當中的例子:

interface Props {
    readonly name: string;
}
interface State {
    readonly color: string;
}
export class Child extends React.Component<Props,State> {
  childMethod() {
    this.props.name = 'jarod'; // ERROR: (props are immutable)
    this.state.color = 'red'; // ERROR: (one should use this.setState)  
  }
}
複製代碼

接口類型

在 TypeScript 中,咱們使用接口(Interfaces)來定義對象的類型。

對象接口

賦值的時候,變量的形狀必須和接口的形狀保持一致。

interface Name {
    first: string;
    second: string;
}

var personName:Name = {
    first: '張三'
} // Property 'second' is missing in type '{ first: string; }' but required in type 'Name'
複製代碼

ts會對每個字段作檢查,若是沒有對接口中聲明的字段進行定義(非可選),能夠看出,定義的變量比接口少一些屬性則會拋出錯誤。

函數接口

接口可以描述JavaScript中對象擁有的各類各樣的外形。除了描述帶有屬性的普通對象外,接口也能夠描述函數類型

interface Lib {
    (): void;
    version: string;
    doSomething(): void;
}

function getLib() {
    let lib = (() => {}) as Lib
    lib.version = '1.0.0'
    lib.doSomething = () => {}
    return lib;
}
複製代碼

函數

函數聲明

function sum(x: number, y: number) {
    return x + y
}
複製代碼

函數表達式

let sum =  (x: number, y: number): number => x + y
複製代碼

可選參數

對於參數,咱們能夠聲明其爲可選參數,即在參數後面加"?"

function buildName(firstName: string, lastName?: string) {
    // ...
}
複製代碼

函數重載

重載容許一個函數接受不一樣數量或類型的參數時,做出不一樣的處理。

function reverse(x: number): number;
function reverse(x: string): string;
function reverse(x: number | string): number | string {
    if (typeof x === 'number') {
        return Number(x.toString().split('').reverse().join(''));
    } else if (typeof x === 'string') {
        return x.split('').reverse().join('');
    }
}
複製代碼

抽象類

抽象類只能在實例中使用,不能直接被實例化。

abstract class Animal {
    eat() {
        console.log('eat')
    }
    abstract sleep(): void
}

class Dog extends Animal {
    constructor() {
        super()
    }
    sleep() {
        console.log('Dog sleep')
    } // 在子類中實現父類中的抽象方法
}
複製代碼

public, private和protected

TypeScript 可使用三種訪問修飾符(Access Modifiers),分別是 public、private 和 protected。

public

public 修飾的屬性或方法是公有的,能夠在任何地方被訪問到,默認全部的屬性和方法都是 public 的

class Animal {
    public name;
    public constructor(name) {
        this.name = name;
    }
}

let a = new Animal('Jack');
console.log(a.name); // Jack
a.name = 'Tom';
console.log(a.name); // Tom
複製代碼

private

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

class Animal {
    private name;
    public constructor(name) {
        this.name = name;
    }
}

let a = new Animal('Jack');
console.log(a.name); // Jack
a.name = 'Tom';

// index.ts(9,13): error TS2341: Property 'name' is private and only accessible within class 'Animal'.
// index.ts(10,1): error TS2341: Property 'name' is private and only accessible within class 'Animal'.
複製代碼

protected

protected 修飾的屬性或方法是受保護的,它和 private 相似,區別是它在子類中也是容許被訪問的

class Animal {
    protected name;
    public constructor(name) {
        this.name = name;
    }
}

class Cat extends Animal {
    constructor(name) {
        super(name);
        console.log(this.name);
    }
}
複製代碼

泛型

定義:不預先肯定的數據類型,具體的類型須要在使用的時候才能肯定

例子: 聲明一個打印函數,實現把傳入的字符串打印出來:

function log(value: string): string {
    console.log(value)
    return value
}
複製代碼

可是這時,加一個需求,要實現能把字符串數組也打印出來:

function log(value: string): string
function log(value: string[]): string[]
function log(value: any): {
    console.log(value)
    return value
}
複製代碼

如上所示,能夠用以前的函數重載來實現。

若是這時,再加一個需求,要實現能把任何類型的參數打印出來。泛型就派上用場了:

function log<T>(value: T): T {
    console.log(value);
    return value;
}
複製代碼

軟件工程中,咱們不只要建立一致的定義良好的API,同時也要考慮可重用性。組件不只可以支持當前的數據類型,同時也能支持將來的數據類型,這在建立大型系統時爲你提供了十分靈活的功能。

後續

Typescript實踐中的進階篇即將到來~

相關文章
相關標籤/搜索