Typescript學習筆記


什么是 TypeScript

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

 

安裝 TypeScript

命令行工具安裝:

npm install -g typescript

編譯一個 TypeScript 文件:

tsc hello.ts

 

 

原始數據類型/ 任意值

為每一個變量提前申明該類型,則該變量取值只能為申明的類型,否則報錯

如果一個變量可以任意取值,可以通過any 申明該變量為任意值

原始數據類型包括:布爾值(boolean)、數值(number)、字符串(string)、nullundefined、Symbol(ES6)共六種

申明為number類型的變量,后面可以取值類型為 number  、nullundefined,會默認進行隱式轉換

 

例子:

let isDone: boolean = false;        //申明該值為 boolean 類型

let decLiteral: number = 6;

let notANumber: number = NaN;       // 進行隱式轉換

let infinityNumber: number = Infinity;  // 進行隱式轉換

let num: number = undefined;   // 進行隱式轉換

let myName: string = 'Xcat Liu';

let u: undefined = undefined;

let n: null = null;
 
let anytest: any = 123;   //申明該值為任意類型
anytest = true;
anytest = '任意值'

//  內置對象類型申明

let b: Boolean = new Boolean(1);    // 申明為 Boolean 類型

let e: Error = new Error('Error occurred');    //申明為錯誤類型

let d: Date = new Date();   // 申明為 時間類型

let r: RegExp = /[a-z]/;    //申明為正則類型

let body: HTMLElement = document.body;
let allDiv: NodeList = document.querySelectorAll('div');
document.addEventListener('click', function(e: MouseEvent) { // Do something });
 

 

 

 

提前申明變量的類型也可以用在functiuon函數傳參,用於規定該參數的類型

在 TypeScirpt 中,可以用 void 表示沒有任何返回值的函數

例子:
function sayHello(person: string) {     // 在函數出入的參數后面申明類型
    return 'Hello, ' + person;
}


function test(): void {     //void 表示該函數沒有返回值
  alert('Hello Wrold');
}

 

 

聯合類型

聯合類型表示取值可以為多種類型中的一種。使用 | 分隔每個類型。

let test: string | number;    //申明 test變量的類型為string 或者 number其中一種
test = 'seven';     //test的取值可以為其中一種類型
test = 7;

 

當不確定一個使用了聯合類型的變量是哪種類型時,只能訪問此聯合類型的所有類型里共有的屬性或方法

function getString(something: string | number) {     //申明傳入的參數為string或者number類型
  return something.toString();        // 只能調用string和number共有的方法
}

 

錯誤例子:

function getLength(something: string | number) {
  return something.length;       // number類型不存在length
}

 

 

對象的類型——接口 (interfaces)

即提前定義一個對象的類型規則,用於申明一個對象時進行類型匹配

interface Person {     //使用interface定義一個對象的類型,取名Person    首字母一般大寫
  name: string;        //申明該對象每個值的取值類型
  age: number;
}

let xcatliu: Person = {     // 申明一個xcatliu對象,使用Person規則進行匹配驗證
  name: 'Xcat Liu',
  age: 25,
};

 

 

 使用Interfaces來定義對象的類型,定義了類型的對象,定義的變量不允許比類型少,也不能多,結構必須一模一樣

錯誤例子:

 

interface Person {
  name: string;
  age: number;
}

let xcatliu: Person = {    //不能比定義的Person類型的變量少
  name: 'Xcat Liu',
};

let xcatliu: Person = {
  name: 'Xcat Liu',
  age: 25,
  website: 'http://xcatliu.com',   /不能比定義的Person類型的變量多
};

 

  

如果我們希望不要完全匹配一個 類型,可以使用可選屬性: 可選屬性的含義是該屬性可以不存在。使用 ?      但是仍然不允許添加未定義的屬性

 

interface Person {
  name: string;
  age?: number;      //在屬性后面加上? 表示該屬性可有可無
}

let xcatliu: Person = {
  name: 'Xcat Liu',
};

 

 

有時候我們希望一個接口允許有任意的屬性,即可以任意添加屬性個數,使用 任意屬性  [propName: string]

一旦定義了任意屬性,那么確定屬性和可選屬性都必須是它的子屬性    任意屬性的取值類型為 any ,否則會跟可選屬性沖突

 

interface Person {
  name: string;
  [propName: string]: any;     // 表示可以任意添加屬性個數  ,添加的屬性類型為 any
}

let xcatliu: Person = {
  name: 'Xcat Liu',
  website: 'http://xcatliu.com',   //任意添加的屬性
  websit2: 'http://xcatliu.com',    //任意添加的屬性
};

 

 對象中的一些字段只能在創建的時候被賦值,那么可以用 readonly 定義只讀屬性,在剛剛創建對象的時候賦值,后面不允許改變該屬性值。也不能在創建的時候未定義值

readonly 定義在屬性的前面,用空格區分

interface Person {
  readonly id: number;   //使用 readonly 定義只讀屬性
  name: string;
}

let xcatliu: Person = {
  id: 89757,
  name: 'Xcat Liu',
};

xcatliu.id = 9527;    //報錯  不能改變該屬性值

 

 

 

數組的類型

數組的類型用於定義申明一個數組時的格式,申明格式類型的數組不能使用其他類型的方法

對象中的接口定義類型方法也同樣適用於數組

 

let testArr: number[] = [1,2,5,4,8]     //申明一個數組的類型為 number

let fibonacci: string[] = ["1","2"];    //申明一個數組的類型為 string

let list: any[] = ['Xcat Liu', 25, { website: 'http://xcatliu.com' }];   // 申明一個數組的類型為任意類型

let fibona: Array<number> = [ 1, 2, 3, 5];   //也可以使用數組泛型Array<elemType> 來表示數組
 interface NumberArray {      //使用接口定義一個數組的類型,表示該數組取值必須為 string 類型
 [index: number]: string;
}
let fi: NumberArray = ["a","1"];

interface NumberArr {        //使用接口定義一個數組的類型,表示該數組取值必須為 number 類型
 [index: number]: number;
}
let fi2: NumberArr = [1, 1, 2, 3, 5];

 

類數組不是數組類型,比如 arguments  ,不能使用數組的類型定義方式

 常見的類數組都有自己的接口定義,如 IArguments, NodeList, HTMLCollection 等

 

function sum() {
  let args: IArguments = arguments;    // arguments是類數組類型,使用 IArguments
}

 

 

函數的類型

定義函數的類型,對函數傳入的參數和返回值做一定的限制

輸入多余的(或者少於要求的)參數,是不被允許的,

function sum(x: number, y: number): number {     //申明一個函數sum  限制其傳入的參數為 number類型,返回的參數為 number類型
  return x + y;
}

sum(1, 2);

 

 

如果是一個函數表達式,,那么需要對左右兩邊進行類型的限制

//申明了一個 mySum函數,申明其類型為number
let mySum: (x: number, y: number) => number = function (x: number, y: number): number {
  return x + y;
};

 

 函數的類型定義同樣可以使用對象的接口

 

interface SearchFunc {      //使用接口申明一個類型,名稱為 SearchFunc
  (source: string, subString: string): boolean;     //申明該函數的傳入值都為 string   返回值為 boolean
}

let mySearch: SearchFunc;     //申明一個函數,使用 SearchFunc 類型規則
mySearch = function(source: string, subString: string) {
  return source.search(subString) !== -1;
}

 

 

函數的類型也可以定義可選的傳入參數, 在參數后面使用 ?

可選參數必須接在必需參數后面

function buildName(firstName: string, lastName?: string) {    // lastName 為可選參數
  if (lastName) {
    return firstName + ' ' + lastName;
  } else {
    return firstName;
  }
}
let xcatliu = buildName('Xcat', 'Liu');
let xcat = buildName('Xcat');

 

 

TypeScript 會將添加了默認值的參數識別為可選參數     使用默認值的可選參數不限制位置

 

function buildName(firstName: string, lastName: string = 'Liu') {     // lastName 為可選參數
  return firstName + ' ' + lastName;
}
let xcatliu = buildName('Xcat', 'Liu');
let xcat = buildName('Xcat');

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(''); } }

 

 

ES6 中,可以使用 ...rest 的方式獲取函數中的剩余參數,items 是一個數組。可以用數組的類型來定義它:

function push(array: any[], ...items: any[]) {     //...items表示剩余參數,是一個數組,可以申明為任意類型的數組
  items.forEach(function(item) {
    array.push(item);
  });
}

let a =  [];
push(a, 1, 2, 3);

 

 

 

類型斷言   <類型>值     值 as 類型

類型斷言可以用來繞過編譯器的類型推斷,手動指定一個值的類型

TypeScript在使用聯合類型時,默認不能引用不確定類型的方法,只能引用共有的方法,某些時刻,我們需要使用類型斷言,即申明此時的屬性為某個類型

類型斷言不是類型轉換,斷言成一個聯合類型中不存在的類型是不允許的   斷言的類型必須是聯合類型中的某一個

function getLength(something: string | number): number {
  if ((<string>something).length) {   // 默認不能使用 length屬性,使用類型斷言 <string>   將此時的something申明為 string類型
    return (<string>something).length;
  } else {
    return something.toString().length;
  }
}

 

 

類型別名

類型別名用來給一個類型起個新名字。使用 type

 

type Name = string;        // 使用 type 將string類型起名為 Name
type NameResolver = () => string;      //另一種寫法
type NameOrResolver = Name | NameResolver;     //使用該別名
function getName(n: NameOrResolver): Name {
  if (typeof n === 'string') {
    return n;
  }
  else {
    return n();   
  }
}

 

 

字符串字面量類型

字符串字面量類型用來約束取值只能是某幾個字符串中的一個。同樣使用 type

type test = 'click'|'scroll'|'mousemove'       // 使用 type 規定test變量為三個值其中一個
function handleEvent(ele: Element, event: test) {   //使用test類型,傳入的值為規定值的其中一個
  // do something
}
handleEvent(document.getElementById('hello'), 'scroll'); 

 

 

 

元組

數組合並了相同類型的對象,而元組(Tuple)合並了不同類型的對象。

簡單理解,在數組類型中,要么規定數組中的每個值都為某種類型,要么都為任意類型。使用元組,可以依次給每個值指定類型

let xcatliu: [string, number] = ['Xcat Liu', 25];

 

 

我們也可以在定義數組類型后,通過索引依次賦值,也可以只賦值其中一項

當直接對元組類型的變量進行初始化或者賦值的時候,需要提供所有元組類型中指定的項。

let xcatliu: [string, number];    //先定義每個值的類型
xcatliu[0] = 'Xcat Liu';     // 通過索引賦值
xcatliu[1] = 25;

xcatliu[0].slice(1);     //可以通過索引調用對應類型的方法
xcatliu[1].toFixed(2);


let xcatliu: [string, number] = ['Xcat Liu']; //報錯,需要全部賦值

 

 

當我們去訪問數組未定義的下標或者對其進行賦值時,它的類型為已存在元素的類型組成的聯合類型,能夠調用的方法為聯合類型共有的方法

let xcatliu: [string, number];

xcatliu = ['Xcat Liu', 25, 'http://xcatliu.com/'];    // 第三個值的類型為 string|number

xcatliu.push(true);     // 報錯   true 是 boolean 類型

console.log(xcatliu[2].slice(1));   // 報錯   slice不是 string|number 共有的方法

 

 

 

TypeScript 中類的用法    public privateprotected

  • public 修飾的屬性或方法是公有的,可以在任何地方被訪問到,默認所有的屬性和方法都是 public 的
  • private 修飾的屬性或方法是私有的,不能在聲明它的類的外部訪問
  • protected 修飾的屬性或方法是受保護的,它和 private 類似,區別是它在子類中也是允許被訪問的

 

 

class Animal {
  public name;           //表示公共的,在任何地方都可以被訪問
  private age;          //表示私有的,不允許被訪問,也不能繼承
  protected height;     //表示受保護的,只能通過繼承訪問
  public constructor(name) {
    this.name = name;
  }
}

var a = new Animal('Jack');
console.log(a.name);        
console.log(a.age);      //報錯,不允許被訪問
console.log(a.height);  // 報錯,只能通過繼承訪問

 

 

abstract 用於定義抽象類和其中的抽象方法 

 抽象類是不允許被實例化的,即不能通過new去實例化,只能被繼承

抽象類中的抽象方法必須被子類實現,即使用abstract 定義為抽象方法,那么必須在子類實現

 

abstract class Animal {
  public name;
  public constructor(name) {
    this.name = name;
  }
  public abstract sayHi();     //抽象方法
}

class Cat extends Animal {
  public sayHi() {     // 繼承 Animal類后實現定義的抽象方法
    console.log(`Meow, My name is ${this.name}`);    
  }
}

let cat = new Cat('Tom');

 

 

 

類實現接口  implements

不同類之間可以有一些共有的特性,這時候就可以把特性提取成接口(interfaces),用 implements 關鍵字來實現。

 

interface Alarm {    //使用 interface 定義了一個接口,里面是一個 alert 方法
  alert();
}

class Door {
}
 
class SecurityDoor extends Door implements Alarm {    // SecurityDoor繼承了 Door類並且引用了 Alarm 接口的方法
  alert() {
    console.log('SecurityDoor alert');
  }
}

class Car implements Alarm {      // Car類 引用了Alarm 接口的方法
  alert() {
    console.log('Car alert');
  }
}

 

 

一個類可以同時引用多個接口

interface Alarm {
  alert();
}

interface Light {
  lightOn();
  lightOff();
}

class Car implements Alarm, Light {
  alert() {
    console.log('Car alert');
  }
  lightOn() {
    console.log('Car light on');
  }
  lightOff() {
    console.log('Car light off');
  }
}

 

 

 接口與接口之間也可以相互繼承:

interface Alarm {
  alert();
}

interface LightableAlarm extends Alarm {
  lightOn();
  lightOff();
}

 

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM