摘要:Typescript可以說是JavaScript的超集,在JS的基礎上新增了許多語法特性,使得型別不再可以隨意轉換,能大大減少開發階段的錯誤。
本文分享自華為雲社群《Typescript基礎語法全解析》,作者:北極光之夜。 。
一.Ts是什麼:
首先,強型別不允許隨意的隱式型別轉換,而弱型別是允許的。JavaScript就是經典的弱型別語言。而Typescript可以說是JavaScript的超集,在JS的基礎上新增了許多語法特性,使得型別不再可以隨意轉換,能大大減少開發階段的錯誤。
二. 基本語法:
1.宣告原始資料型別:
在變數後面指定一個關鍵字表示其只能為什麼型別。
string型別:
const a: string = 'auroras'
number型別:
const b: number = 666 // 包括 NAN Infinity
boolean型別:
const c: boolean = true
null型別:
const d: null = null
undefined型別:
const e: undefined = undefined
symbol型別:
const h: symbol = Symbol()
2.宣告Object型別:
首先,object型別不單單可以指定物件,還可以指定陣列或函式:
const foo1: object = {}; const foo2: object = []; const foo3: object = function(){};
如果只想指定為物件,如下,物件屬性都要提前宣告好型別:
const obj: {name: string,age: number} = { name: '北極光', age:18 }
3.1宣告陣列型別:
可以指定宣告Array且通過<>指定元素型別,比如指定宣告元素都為數字的陣列:
const arr: Array<number> = [1,2,3]
第二種方式如下,也指定宣告元素都為數字的陣列:
const arr: number[] = [1,2,3]
3.2宣告元組型別:
就是要提前指定陣列裡每個元素的型別,嚴格一一對應:
const tuple: [number,string,boolean] = [666,'auraros',true]
4.宣告列舉型別:
通過關鍵字enum宣告一個列舉型別,如:
enum Status { pedding = 1, resolve = 2, reject = '3' } //訪問 console.log(Status.pedding);
如果全不寫值,預設值為從0開始遞增。如果第一個元素為字元型別,就必須全部定義值。如果第一個元素指定為一個數字,後面元素不寫值,那值為第一個元素值按位置大小遞增的結果。
5.函式引數與返回型別:
函式宣告式:
指定函式傳入引數型別,指定返回值型別,呼叫時傳入引數個數與型別都必須相同:
括號裡指定每個引數型別,括號右邊指定返回值的型別。
function fun (name:string,age:number):string{ return 'sss' } fun('auroras',18);
如果傳入引數不確定傳不傳,那麼可以給引數加個‘?’表明它是可選的:
function fun (name:string,age?:number):string{ return 'sss' } fun('auroras');
或者給引數新增預設值,那也會成為可選引數:
function fun (name:string,age:number=666):string{ return 'sss' } fun('auroras');
如果引數個數不確定,可以用擴充套件運算子加解構賦值表示,當然要傳入與指定型別一致的:
function fun (name:string,age:number=666,...res:number[]):string{ return 'sss' } fun('auroras',1,2,3);
函式表示式:
const fun2:(name:string,age:number)=>string = function(name:string,age:number){ return 'sss' }
定義介面時再詳細說。
6.任意型別:
通過指定any關鍵字表示任意型別,跟原來 js 一樣,可以任意賦不同型別的值:
let num:any = 1; num = 'a'; num = true;
7.型別斷言:
型別斷言就是明確的告訴typescript這個變數就是某種型別的,百分之百確定。不用typescript在一些情況下要自己推斷某些沒有明確定義或者多變的場景是什麼型別。
可以通過 as+型別 斷言它就是某種型別的:
const res = 1; const num = res as number;
也可以通過 <型別> 形式斷言(不推薦):
const res = 1; const num = <number>res
8.介面基本使用:
介面可以理解為一種規範,一種契約。可以約束一個物件裡應該有哪些成員,這些成員都是怎麼樣的。
通過interface定義一個Post介面,這個介面是一個物件,規則為有一個name屬性型別為string,age屬性型別為number。
interface Post { name:string; age:number }
然後比如有一個函式 printPost ,它的引數 post 使用我們定義的 Post 介面的規則,那麼呼叫此函式傳參時要傳入符合 Post 介面規則的資料。
interface Post { name:string; age:number } function printPost(post: Post){ console.log(post.name); console.log(post.age); } printPost({name:'asd',age:666})
當然,函式傳參時可能有些引數是可選的,那麼我們可以給介面也定義可選的成員,通過屬性後加一個‘?’指定可選成員:
interface Post { name:string; age:number; sex?:string; } const auroras: Post = { name:'asd', age: 18 }
如果用readonly修飾成員,那麼這個成員屬性在初始化後便不可修改:
interface Post { name:string; age:number; sex?:string; readonly like:string } const auroras: Post = { name:'asd', age: 18, like: 'natrue' } auroras.name = 'aaaa'; //保錯 auroras.like = 'wind';
如果連成員屬性名稱都不確定,那麼可以宣告動態成員,要指定成員名字型別與成員值的型別,如:
interface Post { [prop:string]:string } const auroras: Post = { name:'asd', like: 'natrue' }
9.類基本使用:
描述一類具體事物的抽象特徵。ts增強了es6中class類的相關語法。
首先,類的屬性使用前必須提前宣告好:
class Person { name: string; age: number; constructor(name:string,age:number){ this.name = name; this.age = age; } sayHi(msg:string):void { console.log(`hi,${msg},i am ${this.name}`); } }
10.類的訪問修飾符:
private 修飾私有屬性,只能在類內部訪問。public 修飾公用屬性(預設),外部也可訪問:
class Person { public name: string; private age: number; constructor(name:string,age:number){ this.name = name; this.age = age; } sayHi(msg:string):void { console.log(`hi,${msg},i am ${this.name}`); console.log(this.age); } } const jack = new Person('jack',20); //Person類公有屬性可以訪問 console.log(jack.name); //Person類私有屬性不可以訪問 console.log(jack.age);
protected修飾為受保護的,外部也不可訪問。但與 private 的區別是若是繼承的子類是可以訪問的。
class Person { public name: string; private age: number; // protected protected gender: boolean; constructor(name:string,age:number){ this.name = name; this.age = age; this.gender = true; } sayHi(msg:string):void { console.log(`hi,${msg},i am ${this.name}`); console.log(this.age); } } class children extends Person{ constructor(name:string,age:number){ super(name,age,); //可以訪問 console.log(this.gender); } }
11.類只讀屬性:
給屬性設定 readonly 則為只讀屬性,該屬性初始化後便不可再修改。
class Person { public name: string; private age: number; // readonly protected readonly gender: boolean; constructor(name:string,age:number){ this.name = name; this.age = age; this.gender = true; } sayHi(msg:string):void { console.log(`hi,${msg},i am ${this.name}`); console.log(this.age); } }
12.類與介面:
一些類與類之間有些許共同的特徵,這些共同的特徵可以抽象成為介面。
比如 Person 類和 Animal 類,雖然是不同類,但是人和動物都會吃東西和走路等,這些共同的特徵可以由介面定義。最後一個特徵就定義一個介面。
//吃介面 interface Eat { eat(food:string):void } //行進介面 interface Run { run(behavior:string):void } //人 class People implements Eat,Run { eat(food:string){ console.log(`在餐桌上吃${food}`); } run(behavior:string){ console.log(`站著${behavior}`); } } //動物 class Animal implements Eat,Run { eat(food:string){ console.log(`在地上上吃${food}`); } run(behavior:string){ console.log(`爬著${behavior}`); } }
13.抽象類:
約束子類必須有某些成員,有點類似介面,不同的是抽象類可以包含一些具體的實現。比如動物類應該為一個抽象類,它的子類有貓,狗,熊貓等。它們都是動物,也有一些共同的特徵。定義一個類為抽象類後,就不能再new例項了,只能被其子類繼承。
其中abstract 定義抽象類,類裡用abstract定義一個抽象方法,子類必須實現抽象方法。
abstract class Animal { eat(food:string){ console.log(`在地上吃${food}`); } abstract run (behavior:string):void } //貓 class Dog extends Animal{ run(behavior:string):void{ console.log(behavior); } } const d1 = new Dog(); d1.eat('骨頭') d1.run('四腳爬行') //兔子 class rabbit extends Animal{ run(behavior:string):void{ console.log(behavior); } } const r1 = new rabbit(); d1.eat('蘿蔔') d1.run('蹦蹦跳跳')
14.泛型:
泛型就是在定義函式,介面或者類的時候沒有指定具體型別,等到使用時才指定具體型別。極大程度的複用程式碼。
比如有一個 identity 函式,這個函式會返回任何傳入它的值,且傳入的型別與返回的型別應該是相同的。如果傳入數字,不用泛型的話,這個函式可能是下面這樣:
function identity(arg:number):number{ return arg }
如果傳入字串,這個函式可能是下面這樣:
function identity(arg:string):string{ return arg }
這樣的話太麻煩,所以可以使用泛型,一般用大寫 T 表示泛型,它可以適用於多個型別,且傳入型別與返回型別是相同的。
function identity<T>(arg:T):T{ return arg }