一文看完 Typescript

Typescript

基礎(chǔ)類型

// 布爾 boolean
let flag:boolean = true;

// 數(shù)字類型 number
let num:number = 100;

// 字符串類型 string
let str:string = "Hello";

// 數(shù)組類型 array
let arr:number[] = [1,2,3,4,5];
let arr:Array<number> = [1,2,3,4,5];

// 元組類型 tuple(數(shù)組的增強(qiáng)可指定多種類型)
let arr:[string,number] = [1,"a"];

// 枚舉類型 enum(用于標(biāo)識(shí)狀態(tài)和固定值)
enum Flag{
    success=1,
    error=-1
};
let f:Flag = Flag.success;

enum Color {red=2,blue,orange};     // 如果不定義值,則是其索引值
let c:Color = Color.blue;           // 3,上一個(gè)值有定義則在此基礎(chǔ)上+1

// 任意類型 any(跟js原本的變量無區(qū)別)
let str:any = "Hello";
let num:any = 123;

// null 和 undefined
let num:number | undefined;
num = 123;

// void 類型(無任何值類型,常用于方法無返回值)
function fun():void{
}

// never 從來不會(huì)出現(xiàn)的類型(通常不建議使用)
let num:never;
num = (()=>{
    throw new Error("錯(cuò)誤");
})();

聯(lián)合類型

即允許多個(gè)類型同時(shí)存在

let val:number|string;
val = 123;
val = "Hello";

交叉類型

使用 & 符號(hào)將多個(gè)類型疊加到一起成為的一種新的類型,基包含了多個(gè)類型的所有特性。

interface Student {
    id: string;
    age: number;
}
interface Worker {
    companyId: string;
}

type A = Student & Worker;      // A 此時(shí)包含了 Student 和 Worker 特性
let x: A;
x.age = 5;                      // 合法
x.companyId = 'CID5241';        // 合法
x.id = 'ID3241';                // 合法


// 合并對(duì)象演示
function extend<T, U>(first: T, second: U): T & U {
    let result = {} as T & U    // result 是要返回結(jié)果,類型斷言為 T&U
    for(let id in first){       // 不能將類型 T 分配給類型 T&U,故需使用斷言
        result[id] = first[id] as any
    }
    for(let id in second){
        result[id] = second[id] as any
    }
    return result;              // 返回結(jié)果,類型是 T & U
}
class A{
    constructor(public name: string){}
}
class B{
    constructor(public id:number,public age:number){}
}

let c = extend(new A('Hello'), new B(100,12));
c.name;                         // 'Hello'
c.id;                           // 100
c.age;                          // 12

斷言

斷言不是類型轉(zhuǎn)換,通過斷言告訴編譯器『我完全知道自己在干什么』

// 尖括號(hào)語(yǔ)法
let val: any = "this is a string";
let len: number = (<string>val).length;

// as語(yǔ)法
let val: any = "this is a string";
let len: number = (val as string).length;

顯示賦值斷言

顯式賦值斷言是 TS2.7 引入的一個(gè)新語(yǔ)法。明確告訴編譯器:該屬性或變量已經(jīng)賦過值了。

// 用在類屬性上
class C {
    foo!: number;
    constructor() {
        this.initialize();
    }
    initialize() {
        this.foo = 0;
    }
}

// 用在變量上
let x!: number[];
initialize();
x.push(4);

function initialize() {
    x = [0, 1, 2, 3];
}

函數(shù)

// 參數(shù)和返回值類型都要指定
function run(a:number, b:number):string{
    return a+b.toString();
}

// 可選參數(shù)
function run(a:number, b?:number):string{
    let val = b ? b : a;
    return val.toString();
}

// 默認(rèn)參數(shù)
function run(a:number=100):string{
    return a.toString();
}

// 剩余參數(shù)(擴(kuò)展運(yùn)算符來接收參數(shù))
function run(...arg:number[]):number{
    let result = 0;
    for(let i:number=0; i<arg.length; i++){
        result += arg[i];
    };
    return result;
}

// 函數(shù)重載(即多個(gè)同名函數(shù),但參數(shù)不一樣。即會(huì)出現(xiàn)函數(shù)重載)
function run(a:string):string;
function run(a:number):string;
function run(a:string|number){
    return typeof a === 'string' ? "字符" : "數(shù)字";
};
run("Hello");   // 字符
run(100);       // 數(shù)字

/*
類的三個(gè)修飾符
---
public      公有    在類、子類、類外都可訪問(默認(rèn))
protected   保護(hù)    在類、子類可訪問
priveate    私有    在類可訪問,子類、類外都不可訪問
*/

// 類的基本結(jié)構(gòu)
class Person{
    name:string;                // 屬性,前面省略了 public 關(guān)鍵詞
    constructor(a:string){      // 構(gòu)造函數(shù)

    }
    run():void{                 // 類的方法,前面省略了 public 關(guān)鍵詞
        console.log(this.name);
    }
    static run():void{          // 靜態(tài)方法,通過 Person.run 調(diào)用

    }
}

// 類的繼承
class Person1 extends Person {
    constructor(a:string){
        super(a);               // 調(diào)用父類的構(gòu)造函數(shù)
    }
    work():void{                // 子類自己的方法

    }
}

// 多態(tài),即父類定義一個(gè)方法不去實(shí)現(xiàn),讓繼承它的子類去實(shí)現(xiàn),每個(gè)子類有不同的表現(xiàn)
class Animal{
    name:string;
    constructor(a:string){
    }
    eat():void{                 // 定義一個(gè)方法讓子類去實(shí)現(xiàn)

    }
}
class Dog extends Animal{
    constructor(a:string){
        super(a);               // 調(diào)用父類的構(gòu)造函數(shù)
    }
    eat():void{                 // 子類自己實(shí)現(xiàn)的方法
        console.log("吃骨頭");
    }
}

// 抽象類,即只供其它類繼承使用基類,本身不能被實(shí)例化。使用 abstract 關(guān)鍵字定義抽象類和抽象方法
abstract class Animal{
    name:string;
    constructor(a:string){
        this.name = a;
    }
    abstract eat():void;        // 定義一個(gè)方法讓子類去實(shí)現(xiàn),abstract 方法只可在 abstract 類中
}
class Dog extends Animal{
    constructor(a:string){
        super(a);               // 調(diào)用父類的構(gòu)造函數(shù)
    }
    eat():void{                 // 子類中必須實(shí)現(xiàn)父類中定義的抽象方法
        console.log("吃骨頭");
    }
}

存取器

class A {
    constructor(){}
    private _name:string | undefined;
    set name(str:string) {
        this._name = str;
    }
    get name():string{
        return `My name is ${this._name}`;
    }
}

let a = new A();
a.name = "Andy";
a.name;                         // "My name is Andy"

三斜線指令

僅能放在文件的最頂端才可生效。

/// <reference path="..." />
// 常用于引入 `.d.ts`文件。用于告訴編譯器在編譯時(shí)要引入的額外文件

/// <reference types="node" />
// 引入到聲明文件,表明這個(gè)文件使用了 @types/node/index.d.ts 里面聲明的名字

/// <amd-module name="moduleName" />
// 用于指定 AMD 模塊的名稱(否則默認(rèn)為匿名)

/// <reference no-default-lib="true"/>
// 標(biāo)記為默認(rèn)庫(kù),lib.d.ts 文件就有此項(xiàng)

/// <reference lib="es2017.string" />
// 等效于使用 -lib es2017.string 進(jìn)行編譯

接口

規(guī)范的定義,用于起到限制的作用。接口不關(guān)心內(nèi)部狀態(tài)數(shù)據(jù),也不關(guān)心實(shí)現(xiàn)細(xì)節(jié)。只是限制必須提供某些方法。類于 java,同時(shí)增加了接口類型、函數(shù)、可索引、類等。

// 屬性接口
interface FullName {
    firstName:string;
    secondName?:string; // 可選屬性,該參數(shù)可傳可不傳
}
function fun(name:FullName):void{
    console.log(name.firstName);
}
let obj = {             // 傳入的參數(shù)必須包含 firstName、secondName是可選的
    firstName:"張",
    secondName:"三"
};
fun(obj);

// 函數(shù)類型接口(對(duì)方法傳入的參數(shù)以及返回值進(jìn)行約束)
interface encrypt {
    (key:string, value:string):string;
}
let md5:encrypt = function(key:string, value:string):string{
    return key+value;
}
md5("a","b");

// 可索引接口(約束數(shù)組、對(duì)象)
interface UserArr{              // 約束數(shù)組
    [index:number]:string;
}
let arr:UserArr=['a','b'];

interface UserObj{              // 約束對(duì)象
    [index:string]:string
}
let obj:UserObj={name:'a'}

// 類的類型接口(對(duì)類的約束,和抽象類相似)
interface Animal{               // 約束類
    name:string;
    eat(str:string):void;
}
class Dog implements Animal {   // 實(shí)現(xiàn)接口
    name:string;
    constructor(name:string){
        this.name = name;
    }
    eat(str:string):void{
    }
}

// 接口擴(kuò)展(接口繼承接口)
interface Animal{
    eat():void;
}
interface Person extends Animal {       // 繼承接口
    work():void;
}
class Web implements Person{            // 實(shí)現(xiàn)接口
    name:string;
    constructor(name:string){
        this.name = name;
    }
    eat():void{

    }
    work():void{

    }
}

泛型

解決類、接口方法的復(fù)制用,并對(duì)不特定數(shù)據(jù)類型支持。

// T即是泛型,具體什么類型是調(diào)用這個(gè)方法的時(shí)候決定的 
function fun<T>(value:T):T{         // 定義了傳入與返回的類型一至
    return value;
}
fun<number>(123);                   // 傳入的是數(shù)字,返回也必須是數(shù)字

// 泛型類
class Min<T>{
    list:T[]=[];
    add(value:T):void{
        this.list.push(value);
    }
    min():T{
        let minVal = this.list[0];
        for(let i:number=0; i<this.list.length; i++){
            if(minVal > this.list[i]){
                minVal=this.list[i];
            };
        };
        return minVal;
    }
}
let m1 = new Min<number>();         // 實(shí)例化時(shí)才決定了 T 的類型為數(shù)字
m1.add(1);
m1.add(2);
m1.min();                           // 1

let m2 = new Min<string>();         // 實(shí)例化時(shí)才決定了 T 的類型為字符
m2.add("a");
m2.add("b");
m2.min();                           // "a"

// 泛型接口(方式一)
interface Config{                   // 定義的泛型接口
    <T>(value:T):T;
}
let fun:Config = function<T>(value:T):T {   // 方法實(shí)現(xiàn)跟接口一致
    return value;
}
fun<string>("a");                   // "a",使用時(shí)才決定了其類型
fun<number>(1);                     // 1,使用時(shí)才決定了其類型

// 泛型接口(方式二)
interface Config<T>{                // 定義泛型接口
    (value:T):T;
}
function fun<T>(value:T):T{         // 方法實(shí)現(xiàn)跟接口一致
    return value;
}
let f:Config<string>=fun;           // 決定了其類型
fun("a");                           // "a"

混入 Mixins

類繼承之外的一種通過可重用組件創(chuàng)建類的方式。通過把類當(dāng)成接口,又不實(shí)現(xiàn)其定義的方法并具有混入類的屬性及方法。

class Mixin1{                       // 混入類1
    constructor(public name:string){}
    log1():void{
        console.log("方法一",this.name);
    }
}

class Mixin2{                       // 混入類2
    constructor(public age:number){}
    log2():void{
        console.log("方法二",this.age);
    }
}

class A implements Mixin1,Mixin2 {  // 把 Mixin1、Mixin2 當(dāng)成接口
    name!:string;                   // 定義占位,因?yàn)橐獙?shí)現(xiàn)接口中的屬性
    age!:number;                    // 定義占位,因?yàn)橐獙?shí)現(xiàn)接口中的屬性
    log1!:()=>void;                 // 定義占位,因?yàn)橐獙?shí)現(xiàn)接口中的方法
    log2!:()=>void;                 // 定義占位,因?yàn)橐獙?shí)現(xiàn)接口中的方法
    constructor(name:string, age:number){
        this.name = name;
        this.age = age;
    }
    log():void{
        console.log("自身的方法");
    }
}

// 混入方法,遍歷 Mixins 的所有方法、屬性,并復(fù)制到定義的占位目標(biāo)上去
function applyMixins(base:any, mixins:any[]){
    mixins.forEach(mixin => {
        Object.getOwnPropertyNames(mixin.prototype).forEach(name => {
            base.prototype[name] = mixin.prototype[name];
        });
    });
}
// 應(yīng)用混入
applyMixins(A,[Mixin1,Mixin2]);

let a = new A("Andy",12);
a.log();
a.log1();
a.log2();

文件模塊

// export 可多次調(diào)用
// module.ts
export function module1():any[]{
    return ["a"]
};
export function module2():string{
    return "a";
};
// 或
function module1():any[]{
    return ["a"]
};
function module2():string{
    return "a";
};
export {module1, module2};          // 統(tǒng)一暴露

// main.ts
import {module1, module2 as m2} form "./module";
module1();                          // ["a"]
m2();                               // "a"

// export.default 每個(gè)文件內(nèi)只能用一次
// module.ts
export.default function():void{
}

// main.ts
import module form "./module";
module();

命名空間

與 Java、c# 基本一致

// 命名空間下的接口、類默認(rèn)均為私有
namespace A{
    interface Animal {
        name:string;
        eat():void;
    }
    // 使用 export 暴露出去才可在外部調(diào)用
    export class Dog implements Animal{
        name:string;
        constructor(name:string){
            this.name = name;
        }
        eat(){
        }
    }
}
let d = new A.Dog("2ha");
d.eat();

// 命名空間也可以使用 export 暴露出去被外部調(diào)用
export namespace A{
    interface Animal {
        name:string;
        eat():void;
    }
    export class Dog implements Animal{
        name:string;
        constructor(name:string){
            this.name = name;
        }
        eat(){
        }
    }
}

裝飾器

ES7的標(biāo)準(zhǔn),裝飾器本身就是一個(gè)方法。裝飾器只能用于類、類的方法之上(可多個(gè))。普通函數(shù)不能使用,因?yàn)槠胀ê瘮?shù)存在變量提升。

// 類的裝飾器方法
function logClass(str:string){
    return function(target:Function){
        target.prototype.url = str;
    }
}

@logClass("http://a")
class HttpClient{
    url?:string;
    constructor(){
    }
    getData():void{
    }
}
let http:HttpClient = new HttpClient();
http.url;                           // "http://a"

// 屬性裝飾器
function logProperty(str:string){
    return function(target:any, name:string){
        target[name] = str;         // target 為類的原型對(duì)象
    }
}
class HttpClient{
    @logProperty("a")
    url:string|undefined;
    constructor(){
    }
    getData():void{
    }
}
let http:HttpClient = new HttpClient();
console.log(http.url)               // "a"

// 方法裝飾器(用得較多)
function logFun(str:string){
    return function(target:any,name:string,des:PropertyDescriptor):PropertyDescriptor{
        let oldValue:Function = target[name];
        
        // 修改方法。注意:ES5 、ES6的描述內(nèi)容有差別
        des.value = function(){
            console.log("調(diào)用了裝飾器");
            return oldValue.call(this,str);
        }
        return des;
    }
}
class HttpClient{
    constructor(){
    }
    @logFun("a")
    getData(str:string):string{
        return str;
    }
}
let http:HttpClient = new HttpClient();
console.log(http.getData("b"))               // "a"

// 方法參數(shù)裝飾器(常用來擴(kuò)展類,使用場(chǎng)景較少)
function logParams(str:string){
    return function(target:any,name:string,index:Number):void{
        console.log(target);                // target 類的原型鏈
        console.log(name);                  // name   方法名稱
        console.log(index);                 // index  參數(shù)的索引
    }
}
class HttpClient{
    constructor(){
    }
    getData(@logParams("uuid") uid:string){
    }
}

執(zhí)行順序:屬性裝飾器 > 方法裝飾器 > 方法參數(shù)裝飾器 > 類裝飾器,同一類型裝飾器有多個(gè)則是從后往前執(zhí)行。

Javascript類型檢查

TS在2.3之后版本可以使用 --checkJs 對(duì) .js 文件進(jìn)行類型檢查和錯(cuò)誤提示。

可以通過添加注釋來控制檢查規(guī)則,部分規(guī)則如下:

// @ts-nocheck   忽略類型檢查
// @ts-check     則檢查某些.js文件
// @ts-ignore    忽略本行錯(cuò)誤

https://www.typescriptlang.org/docs/handbook/intro-to-js-ts.html

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容