天天看點

你還在認為TypeScirpt 是 AnyScript ? --《前端那些事》

你還在認為TypeScirpt 是 AnyScript ? --《前端那些事》

前言

聊聊為何要學習TypeScript?

  1. 從開發角度來講,

    TypeScript

    作為強類型語言,對屬性有類型限制。在日常開發中少了減少了不必要的因參數類型造成的

    BUG

    ,當你在使用同僚封裝好的函數時,類型不知道怎麼傳遞,在開發

    TS

    時,它會有很友好類型的提示,此時你就知道該函數需要傳遞哪些參數,并且參數類型是什麼類型。
  2. 從項目結構來講, 使用

    TypeScript

    可以很好的管控項目,通過建立各個子產品的類型管理,通過

    interface

    或者

    類型斷言

    來管理項目中類型,在對應的子產品使用類型,當項目需要疊代更新時,隻需要進行對對應的子產品類型進行更改。
  3. 從前端全局觀來講,社群三大架構早已結合

    TypeScript

    了, 社群也很完善,已經過了

    該不該學習TypeScript 的階段了

去年還有很多朋友猶豫用不用學習

TypeScript

, 很多被社群朋友發的文章誤導,

TypeScript

就是

AnyScript

你還在認為TypeScirpt 是 AnyScript ? --《前端那些事》

TypeScript

對沒有接觸過 強類型語言的朋友有點學習成本,而且在使用

TypeScript

進行開發時,前期可能代碼會很臃腫,讓你覺得看起來有很多

無用的代碼

, 不過在後期,你就可以感覺到

TypeScript

給你帶來的樂趣了。

學會

TypeScript

也對你在職場競争有點優勢,在跳槽時,假如你已經使用

TypeScript

結合 架構 做過一些項目,面試官也會優先考慮你的,薪水進而也提升了。

前端之路還有很長,新的技術/架構更新頻率很快, 最終還是離不開

JavaScript

下面,我們一起來看看

TypeScript

,本文是對标

TypeScript

文檔進行來講解,更加大白話的簡單講述

如何使用TypeScript

.

入手導圖

你還在認為TypeScirpt 是 AnyScript ? --《前端那些事》

TypeScript

一,安裝環境

#npm install -g typescript           

1.1 VSCode 配置自動編譯檔案

#1. 在目錄下  
    tsc --init   自動生成 tsconfig.json 
    tsconfig.json 下 outdir 是輸出的路徑
#2.  任務--- 運作任務   監視 tsconfig.json
           

二,基本文法

2.1 數組

定義使用
// 第一種定義方法   let 數組名:類型[] = []
var arr:number[] = [1,2,3];
console.log(arr);
// 第二種定義方法    let 數組名:Array[類型] = []
var newArr:Array<number> = [1,2,3];
console.log(newArr)           

2.2 元組

它表示 已經 元素的個數和元素類型的數組,各個元素類型可以不一樣。
通路元組長度 和 元素
var strArr:[number,string,boolean] = [22,'測試',false]
console.log(strArr.length)
console.log(strArr[0])
#它隻能按類型的優先順序輸入内容,否則報錯           

2.3 枚舉 enum

enum

類型是對JavaScript标準資料類型的一個補充。
  • 如果沒有給枚舉指定索引的話,預設為 0 , 通過

    枚舉對象[索引]

    可以擷取值
  • 如果指定了枚舉索引為字元串的話,通過

    枚舉.屬性

    擷取的 它的值
enum Sex {Man,Woman}

let m:Sex = Sex.Man;
console.log(m) //0


let w: string = Sex[1]
console.log(w) //Woman


enum Animal {Dog = 3, Cat, Tiger};

console.log(Animal[5]) //Tiger


enum info {student = '學生', teacher = '教師',  parent = '家長' };

console.log(info.teacher)  //教師           

2.4 任意類型 any

any 為 任意類型,一般在擷取dom 使用
// 任意類型
const newArrs:any = ['測試不同資料 ',222,false]
console.log(newArrs)
# 輸出結果為[ '測試不同資料 ', 222, false ]
# 使用場景: 當你不知道類型 或 一個對象 或資料 需要多個類型時,使用any           

2.5 undefined 類型

let num:number | undefined ;
console.log(num) // 輸出 undefined, 但是不會報錯
let newNum:number | undefined = 33;
console.log(newNum)  // 輸出 33            

2.6 never 類型

never 代表不存在的值類型,常用作為 抛出異常或者 無限循環的函數傳回類型
# 應用場景 
    #1. 抛錯誤
    const errDate = (message:string): never => {
        throw new Error(message)
    }
    #2.  死循環
    const date_for = (): never => {
        while(true) {}
    }
    
# never 類型是任意類型的子類型,沒有類型是never 的子類型
别的類型不能指派給never類型, 而 never 類型可以指派給任意類型           

2.7 void 類型

void 為 函數沒有類型,一般用在沒有傳回值的函數
# 如果方法類型為number, 則必須傳回内容, 内容且必須為數字
function add():number{
    return 2323;
}

# 如果方法類型為void,不需要傳回内容
function getAdd():void{
    console.log('測試')
}

# 如果方法類型為any,則可以傳回任意類型
function getAny():any{
    return 999 + 'Hello TypeScript'
}

console.log(getAny())//999 'Hello TypeScript'           

三,類型斷言

什麼是類型斷言?
  • 有時候你在定義一個變量時,起初是不知道是什麼類型,但在使用過程中知道是什麼類型,這時就會用到類型斷言了。
3.1第一種寫法 尖括号
const str = '測試'

const resLength : number = (<string>str).length           
3.2第二種寫法 as
const str = '測試'

const resLength : number = (str as string).length           

四,接口

TypeScript的核心原則之一是對值所具有的結構進行類型檢查。

驗證類型時,順序不影響驗證。

簡單的來說,它是類型限制的定義,當你使用這個定義接口時,它會一一匹對接口中定義的類型。

隻要不滿足接口中的任何一個屬性,都不會通過的。

4.1 接口可選屬性

有時候,接口屬性不是必須全部需要的,滿足某些條件才會需要,這時,就可以采用可選屬性

格式 :

屬性 ?: 類型

interface  Login{
    userName: string,
    password: string,
    auth ?: string
}



function getLogin(obj: Login) {
    if(obj.auth == '管理者') {
        console.log('可以檢視所有菜單')
    } else {
        console.log('您的權限比較低,目前不能檢視')
    }
}


getLogin({
    userName:'zhangsanfeng',
    password: '12121121sd',
    auth: '管理者'
})    //可以檢視所有菜單


getLogin({
    userName:'zhangsanfeng',
    password: '12121121sd'
})    //您的權限比較低,目前不能檢視


           
4.2 接口 隻讀屬性

隻讀屬性: 意味着給屬性指派了後,不可改變。

格式:

readonly 屬性 : 類型

interface Menus {
    readonly title?:string,
    icon?:string,
    readonly path?:string,
    readonly Layout?:string
}


function getMenuInfo(data:Menus){
    console.log(data)
    data.icon = '修改圖示'   // 可以修改
    // data.path = '/home'    報錯,禁止修改,接口屬性為隻讀
    console.log(data)
}


getMenuInfo({
    title: '首頁',
    icon:'homes',
    path:'/home',
    Layout: 'Layput'
})
           
4.3 接口函數類型
用來限制函數傳遞參數類型
  • 函數類型的類型檢查來說,函數的參數名不需要與接口裡定義的名字相比對。
  • (參數1: 類型,參數2:類型) : 傳回值類型

// 擷取使用者資訊
interface UserInfo {
    (name: string,adress: string,phone: number) : string
}

let getUsefInfo:UserInfo = function(name,adress,phone){
    return `${name}住在${adress},手機号為${phone}`
}

console.log(getUsefInfo('張鋒','天津南開區xx小區',188888888))           
4.4 接口可索引類型

在定義一個數組時,可以定義一個 索引類型接口,這樣就限制了它必須傳遞哪些類型的值。

通路:

通過 變量[索引]

interface Code{
    [index : number] : string
}

let errCode : Code = ['200 成功','301 重定向', '400 用戶端錯誤', '500  服務端出錯']

console.log(errCode[3])  //500  服務端出錯           
4.5 類型接口實作
接口描述了類的公共部分,而不是公共和私有兩部分。 它不會幫你檢查類是否具有某些私有成員。
interface Animals {
    eye: number,
    leg: number,  
}


class Dog  implements Animals {
    eye: number;
    leg: number;
    kind: string
    constructor(eye: number, leg: number, kind: string) {
        this.eye = eye
        this.leg = leg
        this.kind = kind
    }
    getDogInfo(){
        console.log(`品種為${this.kind},有${this.eye}隻眼,${this.leg}條腿`)
    }
}

let hashiqi = new Dog(2,4,'哈士奇');
hashiqi.getDogInfo() //品種為哈士奇,有2隻眼,4條腿           
4.6 接口繼承(多合一)
接口之間可以互相繼承,這樣可以更靈活地将接口分割到可重用的子產品裡。
interface Shape1 {
    data: string
}

interface Shape2  extends Shape1{
    code: number
    // Shape2 具有 Shape1 的特征
}


class Message implements Shape2 {
    code: number;
    data: string;
    constructor(code : number,data: string) {
        this.code = code;
        this.data = data
    }
    getCodeInfo(){
        console.log(`狀态碼為${this.code},傳回資訊為${this.data}`)
    }
}


let err = new Message(500,'服務端錯誤')
err.getCodeInfo()  //狀态碼為500,傳回資訊為服務端錯誤           
4.7 接口繼承類

當接口繼承了一個類,那麼接口也會擁有類的屬性和方法。

當别的類 實作這個 接口時,會同時實作 接口的屬性和方法, 繼承類的屬性和方法

class Log {
     time: string = '2020-11-2';
     getLog(){
         console.log('測試')
     }
}

interface  Shape3  extends Log{
    message : string
}



class ErrLog implements Shape3 {
    message: string ;
    time: string;
    constructor(message: string, time: string) {
        this.message = message;
        this.time = time
    }
    getLog(): void {
        console.log("Method not implemented.");
    }
}

let errs = new ErrLog('測試','2020-11-2')
errs.getLog()  //Method not implemented.
           

五,泛型

接觸過JAVA 的同學,應該對這個不陌生,非常熟了。

作為前端的我們,可能第一 次聽這個概念。 通過 字面意思可以看出,它指代的類型比較廣泛。

  • 作用: : 避免重複代碼,代碼備援
但是它和 any 類型 還是有差別的。
  • any 類型: 如果一個函數類型為any,那麼它的參數可以是任意類型,一般傳入的類型與傳回的類型應該是相同的。如果傳入了一個 string 類型的參數,那麼我們也不知道它傳回啥類型。
  • 泛型 : 它可以使

    傳回類型 和 傳入類型

    保持一緻,這樣我們可以清楚的知道函數傳回的類型為什麼類型。
5.1 泛型接口

泛型接口可以這樣了解:

當你需要給接口指定類型時,但目前不知道屬性類型為什麼時,就可以采用泛型接口

你可以給接口指定參數為多個泛型類型,也可以單個;當使用時,明确參數類型即可。

你還在認為TypeScirpt 是 AnyScript ? --《前端那些事》
interface User <T,S,Y> {
     name: T;
     hobby: S;
     age: Y;
 }

 class People implements User<String,String,Number> {
     name: String;
     hobby: String;
     age: Number;
     constructor(name:string,hobby:string,age:number){
         this.name = name;
         this.hobby = hobby;
         this.age = age; 
     }
    getInfo(){
        console.log(this.name+"------------------"+this.hobby)
        console.log(`${this.name}的年齡為${this.age}`)
    }  
 }
 let xiaoZhou =  new People('小周','敲代碼',22)
 xiaoZhou.getInfo() 
 //小周------------------敲代碼
//  小周的年齡為22
           
5.2 泛型函數

定義泛型函數,可以讓 傳入參數類型參數 和 傳回值類型保持一緻。

泛型 标志一般用字母大寫,T 可以随意更換

格式 :  函數名<T> (參數1:T) : 傳回值類型 T           
function genericity<T> (data: T) : T {
    console.log(data)
    return data
}

genericity("測試")
genericity(666)
genericity(['前端','後端','雲端'])

           
5.3 泛型類
  1. 什麼是泛型類
它規定了類中屬性和方法的 類型,而且必須和類型定義的類型保持一緻。
  1. 泛型類的作用
可以幫助我們确認類的所有屬性都在使用相同的類型
  1. 使用格式
class 類名<T> {
 name!: T;
 hobby!: T;
}

# 這樣這個類的所有類型為 number
let 執行個體 =  new 類名<number>();
           
class GenericityA<X>{
    sex!: X;
    age!: X;
}


let gen = new GenericityA<number>();

// gen.sex = '測試'   報錯
gen.age = 3
console.log(gen.age)           
5.4 泛型限制
  1. 接口限制
  • 通過定義接口, 泛型函數繼承接口,則參數必須實作接口中的屬性,這樣就達到了泛型函數的限制
  1. 類限制
  • 通過給類的泛型指定為另一個類,這樣就規定了類泛型的類型都為另一個類
# 第一種
// 定義接口
 interface DataInfo{
     title: string,
     price: number
 }


//  泛型函數 繼承接口,進行對參數類型限制, 如果傳入的參數中,沒有包含接口屬性,則編譯不通過
 function getDataInfos< T extends DataInfo> (obj: T) : T {
     return obj
 }

 let book = {
     title: '前端進階',
     price: 50,  
     author: '小新'
 }

 console.log(getDataInfos(book)) //{ title: '前端進階', price: 50, author: '小新' }           
# 第二種
//  通過類來限制
 class Login{
    username: string;
    password: string;
    constructor(username: string,password:string){
        this.username = username
        this.password = password
    }
 }

class Mysql<T>{
    login<T>(info:T):T{
        return info
    }
}

let  x = new Login('admin','12345');
let  mysql = new Mysql<Login>();
console.log(mysql.login(x)) //Login { username: 'admin', password: '12345' }           

<hr/>

六,類 Class

說到類,做後端的朋友應該都了解,前端 在ES6 中,才出現了 類 Class 這個關鍵詞。

Class 有哪些特征

  • 屬性
  • 構造器
  • 方法
  • 繼承

    extends

  • 屬性 / 方法 修飾符
  • 靜态屬性
  • 抽象類
  • 存取器

    getters/setters

6.1 修飾符

public

共有的
當屬性 / 方法 修飾符為 public 時, 如果前面沒有,預設會加上,我們可以自由的通路程式裡定義的成員。
class Fruit {
    public name: string;
    price: number;
    // 以上為等價
    constructor(name: string, price: number) {
        this.name = name;
        this.price = price
    }
    getFruitInfo(){
        console.log(`您要購買的水果為${name},價格為${this.price}`)
    }
}           

private

私有的
當成員被标記成

private

時,它就不能在聲明它的類的外部通路。
class Fruit {
    public name: string;
    private price: number;

    // 以上為等價
    constructor(name: string, price: number) {
        this.name = name;
        this.price = price
    }
    getFruitInfo(){
        console.log(`您要購買的水果為${name},價格為${this.price}`)
    }
}

const apple = new Fruit('蘋果',22)
// console.log(apple.price)   報錯, 執行個體不可以通路私有屬性
           

protected

受保護的

protected

修飾符與

private

修飾符的行為很相似,但有一點不同,

protected

成員在派生類中仍然可以通路,不可以通過執行個體來通路受保護的屬性。
class A {
    protected name : string;
    protected age : number;
    constructor(name: string , age: number) {
        this.name = name;
        this.age = age
    }
    getA(){
        console.log('A')
    }
}

class B extends A {
    protected job : string;
    constructor(name: string, job: string,age: number) {
        super(name,age)
        this.job = job
    }
    getB(){
        console.log(`B 姓名為${this.name} && 年齡為${this.age} && 職業為${this.job},`)
    }
}

let b = new B('小飛','前端工程師',22)
b.getA()  //A
b.getB()   //B 姓名為小飛 && 年齡為22 && 職業為前端工程師,
// console.log(b.name)  報錯,通路不了,protected成員隻能在派生類中可以通路,不能通過執行個體來通路。           

6.2 靜态屬性

類的靜态成員(屬性 和 方法) 隻能通過 類來可以通路。

定義: static 屬性 / static 方法

class Food {
    public name: string;
    private price: number;
    static adress: string = '四川';
    // 以上為等價
    constructor(name: string, price: number) {
        this.name = name;
        this.price = price
    }
    getFruitInfo(){
        console.log(`您要購買的東西為${name},價格為${this.price}`)
    }
}

const spicy = new Food('辣條',3)

console.log(Food.adress)  //四川
// console.log(spicy.adress)  報錯  類的執行個體對象不可以通路 類的靜态屬性。 隻可以通過類.屬性來通路

           

6.3 繼承

extend

繼承的本意很好了解,當子類繼承了父類,那麼子類就擁有了父類的特征(屬性) 和 行為(方法),
class T {
    name:string;
    constructor(name:string){
        this.name = name
    }
    getNames(){
        console.log('繼承類T')
    }
}

class S extends T {
    constructor(name:string){
        // 派生類擁有T屬性和方法
        super(name)
    }
    getName(){
        console.log(this.name)
    }
}

let  ss = new S('測試繼承')
ss.getName()  
ss.getNames()
// 測試繼承
// 繼承類T           

6.4 抽象類

  • 抽象類可以包含成員的實作細節。

    abstract

    關鍵字是用于定義抽象類和在抽象類内部定義抽象方法。
  • 抽象類中的抽象方法不包含具體實作并且必須在派生類中實作。
abstract class E{
    abstract name: string;
    abstract speak():void;
    abstract play():void;
}


class F implements E {
    name: string;
    constructor(name:string){
        this.name = name
    }
    //  派生類 F 必須實作 抽象類E 的方法和屬性 
    speak(): void {
        console.log('具有聊天功能')
    }
    play(): void {
        console.log('具有娛樂功能')
    }
    get(){
        console.log(this.name)
    }
}


let f = new F('測試');
f.play() //具有娛樂功能
f.get() // 測試
f.speak()  //具有聊天功能           

七,TS 中的函數

函數類型包括

參數類型 和 傳回值類型

7.1 函數添加傳回值類型

每個參數添加類型之後再為函數本身添加傳回值類型.

TypeScript能夠根據傳回語句自動推斷出傳回值類型,是以我們通常省略它。

下面會介紹在TS 中,兩種寫函數的格式

//  第一種寫法
let getInterFaceInfo : (obj:object) => void = function(obj){
    console.log(obj)
}

let infos: object = {
    code: 200,
    message: '發送成功'
}
getInterFaceInfo(infos)


//  第二種寫法
function getCode(code: number, message:string) : void {
    console.log(`code為${code},message為${message}`)
}

getCode(200,'接受成功')               
7.2 函數可選參數 / 預設參數

JavaScript裡,每個參數都是可選的,可傳可不傳。 沒傳參的時候,它的值就是undefined。

在TypeScript裡我們可以在參數名旁使用

?

實作可選參數的功能。
  • 可選參數必須放在必須參數後面。
格式 : 函數名(變量名?:類型):類型 {}             
  • 預設參數,在傳遞參數時,指定預設值
格式 : 函數名(變量名 :類型 = "xx"):類型 {}             
//  可選參數
function getNetWork(ip:string,domain:string,agreement?:string){
    console.log(`ip位址為:${ip},域名為${domain},協定為${agreement}`)
}

getNetWork('127.0.0.1','www.xiaomi.com')  //ip位址為:127.0.0.1,域名為www.xiaomi.com,協定為undefined

// 預設參數
function getNetWorks(ip:string,domain:string,agreement:string = 'http'){
    console.log(`ip位址為:${ip},域名為${domain},協定為${agreement}`)
}
getNetWorks('127.0.0.1','www.xiaomi.com') //ip位址為:127.0.0.1,域名為www.xiaomi.com,協定為http               
7.3 函數剩餘參數

有時,你想同時操作多個參數,或者你并不知道會有多少參數傳遞進來。

在JavaScript裡,你可以使用

arguments

來通路所有傳入的參數。

在TypeScript 中,可以把所有參數集中在一個變量中,前面加上

...

表示 剩餘參數。

注意

  • 直接通過變量通路
  • 也可以通過索引通路
  • 隻能定義一個剩餘參數,且位置在 預設參數和可選參數後面
function getNumberInfo(num:number,...peopleArray: string []) {
    console.log(`人員個數為${num},成員為${peopleArray}`)  // 也可以通過索引來擷取元素
    console.log(`人員個數為${num},成員為${peopleArray[1]}`) 
}

getNumberInfo(4,'小明','小李','小紅','小張')  
//人員個數為4,成員為小明,小李,小紅,小張
//人員個數為4,成員為小李           

八,枚舉

枚舉可以清晰地表達一組對應關系。

TypeScript支援數字的和基于字元串的枚舉。

8.1 數字枚舉

預設枚舉的順序以 0 開頭,然後自動遞增。

枚舉順序也可以指定 值, 指定後,它前面第一個還是以0 遞增

通路

  • 通過

    枚舉名.屬性

    通路到的是

    序号

  • 枚舉名[序号]

    屬性名

enum Sex {
    x,
    man = 4,
    woman 
}

console.log(Sex.x)   //0
console.log(`小紅的性别為${Sex[5]}`) //小紅的性别為woman
console.log(`後端接受小紅的性别ID ${Sex.woman}`) //後端接受小紅的性别ID 5           
8.2 字元串枚舉
enum Job {
    frontEnd = '前端',
    backEnd = '後端'
}

console.log(Job) //{ frontEnd: '前端', backEnd: '後端' }               

九,進階類型

9.1 交叉類型
它指 可以将多個類型合并為一個類型。辨別符為

&

, 當指定一個變量類型為 交叉類型時,那麼它擁有交叉類型的所有屬性,也就是并集。
interface DonInterface {
    run():void;
}
interface CatInterface {
    jump():void;
}
//這裡的pet将兩個類型合并,是以pet必須保護兩個類型所定義的方法
let pet : DonInterface & CatInterface = {
    run:function(){},
    jump:function(){}
}
           
9.2 聯合類型
  • 聯合類型表示一個值可以是幾種類型之一。
  • 用豎線(

    |

    )分隔每個類型。
  • 一個值是聯合類型,我們隻能通路此聯合類型的所有類型裡共有的成員。
function getMenus(info: string | number) {
     console.log(info)
 }


getMenus("測試")
getMenus(2)
// getMenus(false)  報錯           

十,子產品

子產品: 定義的變量,函數,類等等,隻能在自身的作用域裡使用。 如果想在外部通路使用,那麼必須使用

export

将其導出即可。

使用子產品: 通過

import

将子產品内容導入即可使用。
  • 子產品是自聲明的;兩個子產品之間的關系是通過在檔案級别上使用imports和exports建立的。
  • 子產品使用子產品加載器去導入其它的子產品。 在運作時,子產品加載器的作用是在執行此子產品代碼前去查找并執行這個子產品的所有依賴。

10.導出

10.1 導出聲明
任何聲明(比如變量,函數,類,類型别名或接口)都能夠通過添加

export

關鍵字來導出。

導出可以對任何聲明 進行重命名,防止命名沖突, 通過 as 來修改

# 子產品A 檔案

// 導出接口
 export interface A {
     getList() : void
 }

//  導出變量
export const  GET_METHOD =  "get"
 

//  導出類
export class S implements A {
    getList(): void {
        console.log("導出類")
    }
    
}

function getQueryData():void {
    console.log("擷取分頁資料")
}


// 導出子產品 變量重命名
export { getQueryData as getQuery}



# 檔案B
import {getQuery,S,A} from './子產品A';

// 使用子產品中的函數
getQuery()

// 執行個體子產品中類的對象
const a = new S();
a.getList()  // 輸出導出類

// 實作子產品中的 A 接口
class Y implements A {
    getList(): void {
        throw new Error('Method not implemented.');
    }
    
}
           
10.2 組合子產品使用
通常一個大的子產品是多個子子產品組成的。那麼我們可以通過 在大的子產品中導入多個子子產品。

export * from "子產品"

使用組合子產品:

import * as 重命名變量 from ‘組合子產品路徑’

# 子產品C
    //  導出變量
    export const  GET_METHOD =  "get"           
# 子產品B

export const str: string = "B子產品"

export  function getContent():void{
    console.log("我是子產品B的内容")
}           
#組合子產品


 const  res : object =  {
    code: 200,
    message: "請求成功"
 }


export function getRes(): void {
     console.log(res)
 }

 
 # 導出子子產品
 export * from "./modulesC"
 export * from "./moduleB"           
10.3 使用組合子產品
import * as T from "./modulesA";


// C 子產品中的
console.log(T.GET_METHOD)


// B 子產品中的内容
console.log(T.str)  //B子產品
T.getContent() //我是子產品B的内容


// A 子產品中的内容
T.getRes() //{ code: 200, message: '請求成功' }            
10.4 預設導出
每個子產品都可以有一個

default

導出。 預設導出使用

default

關鍵字标記;并且一個子產品隻能夠有一個

default

導出。
#子產品

export interface K {
    name:string;
    birth:string;
}


export default class Student implements K {
    name: string;
    birth: string;
    constructor(name:string,birth:string){
        this.name = name;
        this.birth = birth;
    } 
    getStudentInfo(){
        console.log(this.name+this.birth)
    }
}           
#檔案A
import D,{K} from './modulesD'


//  使用預設導出
 const d = new D('小明','1998')
 d.getStudentInfo()


// 參數類型為接口K 
 function getMessage(obj: K): void {
    console.log(obj)
 }
 let obj = {
     name:"小紅",
     birth: "1998"
 }
 getMessage(obj);           

10.5

export = 和 import = require()

CommonJS和AMD的環境裡都有一個

exports

變量,這個變量包含了一個子產品的所有導出内容。

CommonJS和AMD的

exports

都可以被指派為一個

對象

exports 和 export default

用途一樣,但是

export default

文法不能相容CommonJS和AMD的

exports

在TypeScript 中,為了達到這樣效果,可以這樣寫:

導出:

export =

等于

exports

導入:

import module = require("module")

# 子產品
// 相當于預設導出
export = class Mongodbs{
    host:string;
    user:string;
    password:string;
    port:number;
    databaseName:string;
    constructor(host:string,user:string,password:string,port:number,databaseName:string) {
        this.host = host;
        this.user = user;
        this.password = password;
        this.port = port;
        this.databaseName = databaseName
    }
    query(table:string){
        console.log(`select * from ${table}`)
    }
}
           
#使用子產品

import MogoDb = require("./modulesE")  

const mogodb = new MogoDb('1270.0.1','admin','123456',3006,'TypeScript')

mogodb.query('Vue') //select * from Vue
           

十一, 命名空間

  1. 定義
  • “内部子產品”稱為“命名空間”
  • “外部子產品”稱為“子產品”
  1. 作用
  • 減少命名沖突,将代碼組織到一個空間内,便于通路。
  • namespace 空間名 { }

    ,内部通過

    export

    導出來使用内部成員
namespace XiaoXin {
    export interface  GetData{
        name: string;
        price: number;
        getInfo(obj:object):any;
    }
    export interface  GetMessage {
        code: number;
        message: string;
    }

    export class Book implements  GetData{
        name: string;
        price: number;
        constructor(name:string,price:number){
            this.name = name;
            this.price = price
        }
        getInfo(obj: object) {
            throw new Error("Method not implemented.");
        }
        buyBook(obj: GetMessage) {
            console.log(obj)
        }
    }           
}


const fontEnd = new  XiaoXin.Book("前端開發手冊",99)

var obj = {
    code: 200,
    message:"購買成功"
}

fontEnd.buyBook(obj)  //{ code: 200, message: '購買成功' }


function test(obj:XiaoXin.GetMessage){
    console.log(obj)
}

test(obj)  //{ code: 200, message: '購買成功' }               

11.1 拆分命名空間

當應用變得越來越大時,我們需要将代碼分離到不同的檔案中以便于維護。

我們可以将命名空間檔案拆分成多個檔案,但是它們的命名空間名還是使用的同一個,各個檔案互相依賴使用。但是必須檔案最開頭引入 命名空間檔案。

格式:

/// <reference path="MS1.ts"/>

# 根命名空間
namespace School {
    export const schoolName =  "清華大學"
}           
# 子命名空間1
/// <reference path="MS1.ts" />

namespace School{
    export class Teacher {
        faculty:string;
        name:string;
        age:number;
        constructor(faculty:string,name:string,age:number){
            this.faculty = faculty;
            this.name = name;
            this.age = age
        }
        getInfo(){
            console.log(`${this.name}為${this.faculty},年齡為${this.age}`)
        }
        getSchool(schoole:string){
            console.log(`${this.name}老師就職于${schoole}`)
        }
    }
}           
#  子命名空間2
///  <reference path="MS1.ts" />

 namespace School{
     export class Student{
         name:string;
         age:number;
         hobby:string;
         constructor(name:string,age:number,hobby:string) {
             this.name = name;
             this.age = age;
             this.hobby = hobby;
         }
         getInfo(){
             console.log(`${this.name}是一個學生,年齡為${this.age},愛好是${this.hobby}`)
         }
     }
 }
           
# 使用合并的命名空間


導入命名空間
/// <reference path="MS1.ts" />
/// <reference path="MS2.ts" />
/// <reference path="MS4.ts" />



let teacher = new School.Teacher('計算機教授','張博士',34);
teacher.getInfo() //張博士為計算機教授,年齡為34
teacher.getSchool(School.schoolName)  //張博士老師就職于清華大學


let students = new School.Student('張三',17,'玩LOL');
students.getInfo()  //張三是一個學生,年齡為17,愛好是玩LOL           
編譯命名空間檔案
第一種方法: 會編譯為 一個js檔案
tsc --outFile sample.js Test.ts


第二種方法:  會編譯為多個js檔案,然後通過 <script> src 引入js檔案即可
tsc --outFile sample.js Validation.ts LettersOnlyValidator.ts ZipCodeValidator.ts Test.ts
           

十二,裝飾器

裝飾器是一種特殊類型的聲明,它能夠附加到類聲明、方法、通路符、屬性、類方法的參數上,以達到擴充類的行為。

自從 ES2015 引入

class

,當我們需要在多個不同的類之間共享或者擴充一些方法或行為的時候,代碼會變得錯綜複雜,極其不優雅,這也是裝飾器被提出的一個很重要的原因。
12.1 修飾器分類
  • 類裝飾器
  • 屬性裝飾器
  • 方法裝飾器
  • 參數裝飾器
修飾器寫法: 1. 普通修飾器  (不傳參數)
           2.  裝飾器工廠 (傳參數)           
12.2 類裝飾器

類裝飾器表達式會在運作時當作函數被調用,類的構造函數作為其唯一的參數。

使用場景:應用于類構造函數,可以用來監視,修改或替換類定義。

const extension = (constructor: Function):any => {
    constructor.prototype.coreHour = '10:00-15:00'
  
    constructor.prototype.meeting = () => {
      console.log('重載:Daily meeting!');
    }

  }

@extension
class Employee {
  public name!: string
  public department!: string


  constructor(name: string, department: string) {
    this.name = name
    this.department = department
  }

  meeting() {
    console.log('Every Monday!')
  }

}

let e: any = new Employee('裝飾器', '測試')
console.log(e)  //Employee { name: '裝飾器', department: '測試' }
 console.log(e.coreHour) // 10:00-15:00
 e.meeting()             // 重載:Daily meeting!
             
12.3 類屬性裝飾器
作用于類屬性的裝飾器表達式會在運作時當作函數被調用,傳入下列3個參數

target

name

descriptor

  • target

    : 對于靜态成員來說是類的構造函數,對于執行個體成員是類的原型對象
  • name

    : 成員的名字
  • descriptor

    : 成員的屬性描述符

執行順序: 當調用有裝飾器的函數時,會先執行裝飾器,後再執行函數。

通過修飾器完成一個屬性隻讀功能,其實就是修改資料描述符中的

writable

的值 :
function readonly(value: boolean){
    return function(target:any,name:string,descriptor:PropertyDescriptor) {
        descriptor.writable = value
    }
}


class Student{
    name:string;
    school:string = '社會大學'
    constructor(name:string) {
        this.name = name
    }
    @readonly(false)
    getDataInfo(){
        console.log(`${this.name}畢業于${this.school}`)
    }
}

let sss = new Student('小李子')
// 報錯,  隻能讀,不能修改
// sss.getDataInfo = () => {
//     console.log("測試修改")
// }

sss.getDataInfo()           

十三,TS + Vue 環境搭建

13.1 更新Vue-cli

1. 先 解除安裝舊的版本
npm uninstall -g @vue/cli 
#or
yarn global remove @vue/cli

2.安裝最新版本
npm install -g @vue/cli
# OR
yarn global add @vue/cli
           

13.2 建立項目

vue create  projectname   項目名必須小寫           

13.3 關閉變量未聲明報錯

打開 package.json ,修改rules  内容,改為如下:
    "rules": {
      "no-unused-vars": 0
    }

這樣就關閉了           

更多精彩文章在首頁

最後

文中如有錯誤,歡迎碼友在評論區指正,如果對你有所幫助,歡迎點贊和關注~~~