大前端進階-TypeScript

概述

TypeScript是JavaScript的超集,也就是說TypeScript不只包含了JavaScript的所有內容,同時也包含其餘內容。typescript

TypeScript = JavaScript + 類型系統 + ES6+新特性支持。

原始類型

TypeScript原始類型能夠和JavaScript基礎類型一一對應。數組

const a: number = 1 // NaN
const b: string = 'foo'
const c: boolean = true // false
const d: void = undefined
const e: null = null
const f: undefined = undefined
const g: symbol = Symbol()

數組類型

const arr1: Array<number> = [1, 2]
const arr2: string[] = ['foo', 'bar']

元組類型

指的是明確數量和類型的數組。函數

const arr: [number, string] = [1, 'foo']
// 能夠經過如下方式正常獲取數組中的元素
console.log(arr[1])
const [num, str] = arr

object類型

const obj: object = {}
obj['name'] = 'zhangsan'

枚舉類型enum

枚舉類型指的是經過enum關鍵字定義一組鍵值對數據,數據定義完成後只能讀取,不能修改。post

// 文章狀態
enum PostStatus {
    // 草稿
    Draft = 0,
    // 未發佈
    Unpublished = 1,
    // 已發佈
    Published = 2
}

const post = {
    title: 'typescript',
    status: PostStatus.Published
}
// 直接經過enum聲明的枚舉類型能夠用數字獲取枚舉名稱
console.log(PostStatus[0]) // Draft

常量枚舉:在enum關鍵字前面加上constthis

// 文章狀態
const enum PostStatus {
    // 草稿
    Draft = 0,
    // 未發佈
    Unpublished = 1,
    // 已發佈
    Published = 2
}

// 此時再用數字獲取枚舉值就會報錯
console.log(PostStatus[0])

Never

never表示永遠不存在值的類型,一般用於老是拋出異常或者永遠不會有返回值的函數的返回值類型。rest

// 拋出異常
function fn(): never {
    throw new Error()
}
// 永遠不會有返回值
function fn1(): never {
    while (true) { }
}

函數類型

// 能夠在聲明函數的時候用註解的方式爲參數和返回值添加類型
function sum(a: number, b: number): number {
    return a + b
}
// 也能夠用箭頭函數表示函數類型
const sum1: (a: number, b: number) => number
    = function (a, b) {
        return a + b
    }
// 函數聲明後,調用時只能傳入與聲明相對應的參數類型和參數數量
// 或者使用可選參數和剩餘參數
function test(a?: number, ...rest: number[]) {
    // todo
}

在TypeScript中能夠爲同一個函數提供多個函數類型定義來進行函數重載code

// 重載一
function test(x: number): number;
// 重載二
function test(x: string): string;
// 並非重載的一部分,只是實現邏輯
function test(x: any): any {
    if (typeof x === 'number') {
        return x
    } else if (typeof x === 'string') {
        return x
    }
}
test(1)
test('foo')

任意類型

ts中可使用any表示任意類型,提供any主要是爲了兼容老的js代碼。對象

let a: any = 1
// 能夠改變a的類型
a = 'foo'

類型推斷

當未改變量指明類型的時候,ts能夠經過參數值推斷參數類型。繼承

// 此時會自動推斷a的類型爲number
const a = 1

類型斷言

ts中能夠手動指定變量的類型。索引

const a: number | undefined = undefined
// 將a的類型轉爲指定爲number
let b: number = a as number
let c: number = <number>a

接口

能夠經過interface關鍵字設置對象必須知足某種要求。

const enum PostStatus {
    // 草稿
    Draft = 0,
    // 未發佈
    Unpublished = 1,
    // 已發佈
    Published = 2
}
// 要求文章必須具有title,status, id屬性,能夠有subtitle屬性,其中id爲只讀屬性
interface Post {
    title: string
    subtitle?: string
    status: PostStatus,
    readonly id: number
}
let obj: Post = {
    title: 'typescript',
    status: PostStatus.Draft,
    id: 1
}
// 只讀屬性不能修改
obj.id = 2

針對cache這種屬性不肯定的對象,可使用動態成員。

interface ICache {
    // 要求屬性和屬性值均爲字符串
    [key: string]: string
}

let cache: ICache = {}
// 能夠在使用的時候給對象添加符合要求的屬性
cache['foo'] = 'bar'

TypeScript在ES2015的class類基礎上添加了一些關鍵字,用於描述類的類型。

class Person {
    name: string
    // 私有屬性,外部沒法訪, 能夠添加readonly使其變爲只讀屬性
    private readonly type: string = 'person'
    // protected 受保護,只能在內部和子類內部使用
    protected field: string = 'foo'
    constructor(name: string) {
        this.name = name
    }

    sayHi(msg: string) {
        // 能夠在類內部訪問私有屬性
        console.log(`my name is ${this.name}, i am a ${this.type}, ${msg}`)
    }
}

class Student extends Person {
    constructor(name: string) {
        super(name)
    }

    sayHi() {
        // 能訪問父類受保護的屬性,可是不能訪問私有private屬性
        console.log(this.field)
    }
}

當privite用在constructor前面時,那麼這個類就不能在其餘地方使用new生成實例。

class Book {
    title: string;
    private constructor(title: string) {
        this.title = title
    }
    // 可經過靜態方法提供實例化對象的途徑
    static create(title: string) {
        return new Book(title)
    }
}
const ts = Book.create('TypeScript')

同時,類能夠繼承接口,表示類須要具有某些方法或者屬性。

interface IBook {
    getContent(): string
}

// 類能夠繼承多個接口
class Book implements IBook {
    title: string;
    constructor(title: string) {
        this.title = title
    }
    // 必須實現接口
    getContent(): string {
        return `TypeScript is a Language`
    }
}

抽象類

抽象類聲明和普通類類似,只不過抽象類不能實例化,同時抽象類中的抽象方法須要子類實現。

abstract class Person {
    name: string;
    // 抽象屬性
    abstract field: string
    constructor(name: string) {
        this.name = name
    }
    // 抽象方法
    abstract sayHi(msg: string): void
}

class Student extends Person {
    field: string = 'test';
    sayHi(msg: string): void {
        console.log(msg)
    }
}

泛型

泛型能夠理解爲將可變化的類型看成一個參數

const createNumberArray = function(length: number, value: number): number[] {
    return Array(length).fill(value)
}
const arr = createNumberArray(2, 1) // [1, 1]

const createStringArray = function(length: number, value: string): string[] {
    return Array(length).fill(value)
}
const arr1 = createStringArray(2, 'foo') // [foo, foo]

在上面的例子中,createNumberArray和createStringArray除了參數和返回值的類型不一樣以外,其他都同樣,此時就可使用範型。

function createArray<T>(length: number, value: T): T[] {
    return Array(length).fill(value)
}
// 在使用時指定類型
const arr = createArray<number>(2, 1) // [1, 1]
const arr1 = createArray<string>(2, 'foo') // [foo, foo]
  • 在聲明範型的時候,能夠爲類型添加約束。
interface Person {
    name: string
}
// 經過extends爲類型添加約束,要求類型必須實現了Person接口
function intro<T extends Person>(person: T) {
    return person.name
}
intro({ name: 'zs' }) // ok
intro(5) //error number類型沒有實現Person
  • 聲明範型的時候,能夠添加一個被另外一個類型參數約束的類型參數。
interface Person {
    name: string,
    age?: number
}
// 此範型要求T必須實現Person, U必須是T的屬性中的某一個
// keyof是索引類型查詢操做符,假設T是一個類型,那麼keyof T產生的類型是T的屬性名稱字符串字面量類型構成的聯合類型
function intro<T extends Person, U extends keyof T>(person: T, key: U) {
    return person[key]
}
intro({ name: 'zs' }, 'name')

// 至關於
function intro<T extends Person, U extends 'name' | 'age'>(person: T, key: U) {
    return person[key]
}
  • 在範型中還可使用類類型
class Person {
    constructor() { }
}
function create<T>(c: { new(): T; }) {
    return new c()
}

const zs = create<Person>(Person)

類型聲明declare

import { camelCase } from 'lodash'
// 當引用相似lodash這種沒有類型聲明文件的第三方庫時,若是不明確聲明引入的變量的類型,將會報錯
declare let camelCase = (str?: string) => string
console.log(camelCase('hello typescript'))

一般類型聲明會放入*.d.ts文件中

相關文章
相關標籤/搜索