TypeScript是由微軟開發的一個JavaScript超集,主要提供了類型系統和對ES6的支持。正如TypeScript的官網所說:node
TypeScript is a typed superset of JavaScript that compiles to plain JavaScript.譯:TypeScript是JavaScript的類型化超集,可以編譯爲純JavaScript語言。typescript
使用TypeScript,可以校驗變量的類型,正由於可以校驗變量的類型,它彌補了JavaScript的語法中,弱類型、動態類型語言的缺陷。TypeScript聲明的變量是一種靜態類型,在代碼編譯時報錯,相比JavaScript的運行時報錯,可以提早發現代碼錯誤,及時糾正。npm
TypeScript靜態類型不只指變量的類型不可修改,同時也說明,變量中存在的方法和屬性也基本肯定了下來。canvas
如下是對TypeScript語法的基礎知識的梳理,包含的內容如思惟導圖所示。
數組
安裝TypeScript以前,先安裝一下node。
全局安裝TypeScript函數
npm install typescript -g
可能這樣會報沒有權限的錯誤,這時在前面加sudo(mac爲例),而後輸入密碼能解決這個問題。若是要安裝指定版本,加@版本號。優化
sudo npm install typescript@3.6.4 -g
新建一個ts文件this
mkdir demo1.ts
裏面先寫點東西,以方便後面的操做。spa
const count11: number = 1; console.log(count11);
而後命令行執行:插件
tsc demo1.ts
tsc表示把ts文件編譯成js文件。隨後能夠看到目錄中多出一個demo1.js的文件,接着執行:
node demo1.js
在控制檯中能看到打印出的1,就是count11這個變量值。
至此,能夠看到從編譯ts文件到控制檯打印輸出結果,須要分兩步,但這裏有個更好的方法,全局安裝一個叫ts-node的插件能夠進行優化,直接在控制檯輸出結果,但沒法生成編譯後但js文件。
這裏須要注意的是,須要全局安裝ts-node,試過局部安裝了一下行不通。
全局安裝ts-node
sudo npm install ts-node -g
而後想要執行哪一個文件,就直接:
ts-node 那個文件.ts
TypeScript的靜態類型包括基礎類型和對象類型,基礎類型有number、string、void、boolean、null、undefined......對象類型有對象、數組、類、函數。
// 基礎類型舉例 const num1: number = 1; // number const str1: string = 'abcd'; // string const nothing: null = null; //null const uf: undefined = undefined; // undefined const right: true = true; // boolean function func1(): void { // void,表示函數沒有返回值 console.log('void'); } console.log(num1, str1, nothing, uf, right); func1();
// 對象類型舉例 // 對象 const obj1: { height: number, width: number } = { height: 100, width: 100 }; // 數組 const arr1: number[] = [1, 2, 3]; // 這裏表示的是數組每一個元素都是number類型 // 類 class Geometry { vector: number; face: number } const geom1: Geometry = new Geometry(); geom1.vector = 8; geom1.face = 6; // 函數 const addXY: (x: number, y: number) => number = (x, y) => { return x + y; } // 上面函數等價於 const addXY = (x: number, y: number): number => { return x + y; } console.log(obj1.height, obj1.width); console.log(arr1); console.log(geom1.vector, geom1.face); console.log(addXY(1, 1));
類型註解的意思是,須要明確地寫出變量的類型,而類型推斷指的是不須要明確地指定變量的類型。通常可以由Typescript進行類型推斷的變量不須要進行類型註解,這個最多見的就是直接像JavaScript那樣聲明賦值給了一個變量,那麼TypeScript就能夠推斷這個變量是對應的類型,怎麼檢測到這個變量的類型呢?使用vs code能夠查看。
舉個例子。
一、類型註解的例子
// 類型註解 let num2: number; num2 = 2;
若是是聲明、賦值分開寫,又沒有類型註解,則沒法作到類型推斷,這時,類型是any。
// 沒法進行類型推斷 num2的類型顯示any let num2; num2 = 2;
二、類型推斷的例子
// 類型推斷 let num3 = 133;
// 類型推斷 const obj2 = { left: 50, top: 100, radius: '50%' }
如下這個例子,說明了ts沒法分析變量的類型,致使變量類型成了any。因此這裏是須要用類型註解的。
function addXY2(x, y) { return x + y; } const totals2 = addXY2(1, 7);
使用了類型註解後,totals2變量類型肯定了,而不是以前的any。
function addXY2(x: number, y: number) { return x + y; } const totals2 = addXY2(1, 7);
前面寫過靜態類型爲函數類型,指的是一個函數做爲變量,也就是變量是函數類型的變量。而這裏的函數相關類型指的是一個函數自身,內部的返回值類型和函數參數的解構。
函數的返回值能夠是靜態類型,好比number、string、boolean、類class、數組等等。
function addXY3 (x: number, y: number): number[] { return [x + y]; } const totals3 = addXY3(1, 8); console.log(totals3);
function addXY3 (x: number, y: number): string { return x + y + 'px'; } const totals3 = addXY3(1, 8); console.log(totals3);
class computedWidth { width: number; } function addXY3 (x: number, y: number): computedWidth { return { width: x + y }; } const totals3 = addXY3(1, 8); console.log(totals3);
有兩個特殊的須要注意一下。
void指的是函數沒有返回值,一般在寫JavaScript的代碼時,寫的函數會存在沒有返回值的狀況,這時使用void便能很好地指明函數沒有返回值,一旦不當心多寫了return xxx; 便會報錯,及時糾正。
never指的是函數永遠不會執行到最後。
// never function addXY5(x: number, y: number): never { throw new Error(); console.log(x + y); // 這一行沒法執行到 }
當函數的參數是一個對象的時候,須要注意參數的解構賦值。以前有寫過函數的參數的類型註解,但那些都是像number、string這樣的類型,而像對象類型的參數的類型註解尚未提過。
若是參數是對象類型,須要這樣寫。
// 函數參數解構正確寫法 function addXY4({ x, y }: { x: number, y: number }): number { return x + y; } const totals4 = addXY4({ x: 2, y: 7 });
而不是這樣寫,會報錯。
// 函數參數解構錯誤寫法 function addXY4({ x: number, y: number }): number { return x + y; } const totals4 = addXY4({ x: 2, y: 7 });
// 數組 const strArr: string[] = ['a', 'c', 'b']; const arrAny: (number | string | boolean)[] = ['1', 2, true]; const objArr: { width: number, height: number }[] = [{ width: 100, height: 100 }];
// 使用類型別名 type type ComputedArea = { width: number, height: number }; const objArr2: ComputedArea[] = [{ width: 50, height: 10 }];
// class的狀況 class Geometry{ left: number; top: number; id: string; } const geomList1: Geometry[] = [ { left: 100, top: 100, id: 'AB001' }, new Geometry() ]; geomList1[1].left = 200; geomList1[1].top = 200; geomList1[1].id = 'AB002'; console.log(geomList1);
//元組,與數組的區別是元素的類型按順序指定,不可錯位 const student1: [string , string , number] = ['a001', 'Tom', 23];
// 寫個複雜點的 const studentList1: [string, string ,number][] = [ ['a001', 'Tom', 22], ['a002', 'Jerry', 23], ['a003', 'Jane', 23] ] console.log(studentList1);
interface接口的做用是把一些共有的屬性和方法提出來放到接口裏面,接口可供變量使用,做爲一個對象類型(對象、函數等)。interface與type類型別名的區別是,interface只能是對象類型,而type能夠是其餘的基礎類型,不單是對象類型。
接口能夠定義只讀模式的屬性,使用readonly標識。
接口中的屬性有時不是全部使用這個接口的變量都須要,這時能夠在屬性名與冒號之間加上一個問號「?」,這個屬性將做爲可選屬性使用。
有時使用接口的變量有本身的屬性,而不是接口中定義的,這時,若是在接口中加上[propName: string]: any,將表示使用這個接口的變量能夠自定義本身的屬性而不須要在接口中存在。
以上所列出的接口的一些特色,在如下的代碼中舉了些例子。
interface Person { name: string, age?: number, readonly id: string, [propName: string]: any } function getName (person: Person): string { return person.name; } function setName (person: Person, name: string): void { person.name = name; } const Jane = getName({ name: 'Jane', age: 23, id: '0a001', weight: '60kg' }); const resetJane = setName({ name: 'Jane', id: '0a002' }, 'Tom');
class John implements Person { name: 'abcd'; id: '0a003'; }
// interface interface Person { name: string, age?: number, readonly id: string, [propName: string: any } interface female extends Person { tall: string }
// 類的定義 class Geometry { counts = 7; getCounts() { return this.counts; } } const geom6 = new Geometry(); console.log(geom6.getCounts());
// 類的繼承 class Geometry { counts = 7; getCounts() { return this.counts; } } class Vector2 extends Geometry { getVectors () { return 8; } } const geom6 = new Vector2(); console.log(geom6.getCounts()); console.log(geom6.getVectors());
若是在子類裏面又重寫了一遍父類的方法或屬性,子類的會覆蓋父類的。
class Vector2 extends Geometry { counts = 0; getCounts() { return this.counts; } getVectors () { return 8; } }
若是不想子類裏重寫的方法、屬性覆蓋父類,那麼能夠使用super。
class Geometry { counts = 7; getCounts() { return this.counts; } } class Vector2 extends Geometry { getCounts() { return super.getCounts() + 9; } getVectors () { return 8; } } const geom6 = new Vector2(); console.log(geom6.getCounts()); console.log(geom6.getVectors());
// 類的訪問類型--public class Canvas1 { width: string; // 默認是public public height: string; // 能夠在子類、類的外部使用 getWidth() { return this.width; } } class SubCanvas1 extends Canvas1 { getHeight() { console.log(this.height); } } const subCanvas1 = new SubCanvas1(); subCanvas1.height = '100px'; console.log(subCanvas1.height);
// 類的訪問類型--private class Canvas1 { private width: string; // 只容許類內使用,在子類或類的外部使用都不行 public height: string; getWidth() { return this.width; } }
// 類的訪問類型--protected class Canvas1 { private width: string; // 只容許類內使用 public height: string; getWidth() { return this.width; }; protected background: string; // 容許在類的內部及子類中訪問,類外不可訪問 } class SubCanvas1 extends Canvas1 { getHeight() { console.log(this.height); } getBackground() { console.log(this.background); } }
// 類的構造器 class Canvas2 { // 傳統寫法 public width: string; constructor(width: string) { this.width = width; } } const canvas2 = new Canvas2('100px'); console.log(canvas2.width);
// 類的構造器 class Canvas2 { // 簡化寫法 constructor(public width: string) {} } const canvas2 = new Canvas2('100px'); console.log(canvas2.width);
// 子類有構造器,那麼子類要手動調用一下父類的構造器,不管父類有沒有寫構造器 class Canvas2 { // 簡化寫法 constructor (public width: string) {} } class SubCanvas2 extends Canvas2 { constructor (public id: number) { super('100px'); // 手動調用父類構造器,有參傳參 } } const subCanvas2 = new SubCanvas2(10001); console.log(subCanvas2);
至此,最近學的ts基礎語法筆記已記錄完畢,後續會對進階的知識作補充。