前段時間有朋友和我推薦 TypeScript
,他說寫起來特別爽,讓我去試一試,那時候我還在那是啥高深莫測的東西。恰好那段時間忙,一直沒有時間看。最近也很忙,仍是抽時間來探一探 TypeScript
;簡單說 ts
主要提供的是 dynamic type check
,提供的 interface
接口這個功能在開發項目的時候會頗有幫助。TypeScript
是 JavaScript
的一個超集。他和 JavaScript
有着千絲萬縷的關係。前端
TypeScript
相關命令java
tsc -init //ts文件編譯成js文件
tsc -w //實時監控文件編譯,即一遍寫ts代碼保存的時候就能夠看到js代碼
複製代碼
運行了 tsc -init
之後會生成一個 tsconfig.json
配置文件web
JavaScript
裏面最基本的單位,我首先從函數入手慢慢的去學習更多的
TypeScript
語法,進而進一步掌握
ts
的用法;
須要驗證函數參數類型,最基本的包括,string
和 number
,string[]
,number[]
,還有元組( = > 進入元組的學習=>基本類型的學習) 和 JavaScript
同樣,TypeScript
函數能夠建立有名字的函數和匿名函數編程
function add(x:number,y:number):number {
return x + y
} //有名函數
let myAdd = function(x:number,y:number):number {
return x + y
} //匿名函數
複製代碼
咱們只對代碼右側的匿名函數進行了類型定義,而等號左邊的 myAdd
是經過賦值操做進行類型推斷出來的,書寫完整的函數類型。(類型推斷:若是沒有明確的指定類型,那麼 TypeScript
會依照類型推論(Type Inference
)的規則推斷出一個類型。)json
let myAdd: (x:number,y:number) => number =
function(x: number,y:number):number { return x + y}
複製代碼
函數類型包含兩部分: 參數類型和返回值類型;在 TypeScript
的類型定義中, => 用來表示函數的定義,左邊是輸入類型,須要用括號括起來,右邊是輸出類型,和 ES6
的箭頭函數不同後端
TypeScript
裏的每個函數參數都是必須的,傳遞給函數的參數個數必須與函數指望的參數個數一致,不然會報錯。數組
必填參數bash
function buildName(firstName:string,lastName:string) {
return firstName + " " + lastName
}
let result0 = buildName(12, 12); //提示 12 類型的參數不能賦值給 string
let result1 = buildName('Bob') //提示應該有兩個參數,可是隻得到一個
let result2 = buildName('Bob','Adams','"sr') //提示應該有兩個參數,可是隻得到三個
let result3 = buildName("Bob", "Adams"); //參數和傳入的參數同樣,不提示
複製代碼
可選參數數據結構
實現參數可選功能,咱們須要在參數名旁邊加 ?
,可是可選參數必須跟在參數後面dom
function selectParam(firstName:string,lastName?:string) {
return firstName + " " + lastName
}
let selectParam1 = selectParam('bob')
let selectParam2 = selectParam('bob','Adam')
let selectParam2 = selectParam('bob','Adam') //兩個變量沒法從新聲明
複製代碼
默認參數
咱們能夠爲參數提供默認值,若是帶默認值的參數出如今必須參數前面,用戶必須明確的傳入 undefined
值來得到默認值
function param(firstName:string,lastName = 'Smith') {
return firstName + ' ' + lastName
}
let param1 = param('bob')
let param2 = param('bob','Adam','kk') //提示參數應該是1-2個
複製代碼
剩餘參數
必要參數,默認參數和可選參數都是表示某一個參數,有時候不知道要操做多少個參數,咱們能夠用 ...
來操做剩餘參數
function restParam (firstName:string,...restOfName:string[]) {
return firstName + " " + restOfName.join(' ')
}
let employName = restParam ('Joseph',"Samuel","Bob")
//restParam 能夠換一種形式
let restParamFun:(fname:string,...rest:string[]) => string = restParam
複製代碼
this
和 箭頭函數(這裏好像有問題,待修改)在 JavaScript
裏面 this
的值在函數被調用的時候指定。但 TypeScript
建立時候指定的
interface Card {
suit: string;
card: number;
}
interface Deck {
suits: string[];
cards: number[];
createCardPicker(this:Deck):()=>Card; //this 指向 Deck
}
let deck:Deck = {
suits:['hearts','spades','clubs'],
cards:Array(52),
createCardPicker:function(this:Deck) {
return () => {
let pickedCard = Math.floor(Math.random()*52)
let pickedSuit = Math.floor(pickedCard / 13);
return { suit: this.suits[pickedSuit],card:pickedCard % 13}
}
}
}
let cardPicker = deck.createCardPicker();
let pickedCard = cardPicker();
alert("card: " + pickedCard.card + " of " + pickedCard.suit);
複製代碼
若是是 JavaScript
會報錯,此時 this
指向了 window
,可是TypeScript
不會報錯,他指定了 this
會在哪一個對象上面調用
在 JavaScript
的類型分爲兩種:原始數據類型(Boolean
,number
,string
,null
,undefined
,Synmbol
)和對象類型,在 TypeScript
中原始類型數據也是使用。爲了讓程序有價值,咱們須要可以處理最簡單的數據單元,數字,字符串
let decLiteral:number = 6 //數字類型
let name1:string = 'bob' //字符串類型
let sentence:string = `Hello, my name is ${name1}` //字符串模板
let list0:number[] = [1,2,3,4] //[]形式定義數組
let list1:string[]=['12','12','90']
let list2:Array<number> = [1,23,4] //Array<元素類型>
let list3:Array<string> = ['1','23','4'] //Array<元素類型>
複製代碼
在 TypeScript
中數組類型有多重定義方式,比較靈活
- 類型 + 方括號 表示法
let fibonacci:number[] = [1,2,3,4]//只能傳number類型的,不然會提示錯誤
複製代碼
- 2.數組泛型 (=> 跳到泛型去學習)
let fibinacci: Array<number> = [1,2,3,4]
複製代碼
- 3.用接口表示數組 (=> 跳到接口去學習)
interface NumberArray {
[index:number]: number
}
let fibonacci: NumberArray = [1,2,3,4]
複製代碼
NumberArray
表示:是一個數字數組,index
是數組的索引類型,: 後面表示是一個數字組成的數組(這樣表述好像還有點怪,歡迎指正)
Tuple
元組類型容許表示一個已知元素數量和類型的數組,各元素的類型沒必要相同(數組合並了相同類型的對象,而元組合並了不一樣類型的對象)
let x:[string,number];
x = ['Hello',10]
複製代碼
好比說一週只有七天
enum Color { Red,Green,Blue}
let c:Color = Color.Green
複製代碼
any
在編程階段還不清楚類型的變量指定一個類型,值多是動態輸入,可是 Object
類型的變量值容許你給她賦任意的值,不能在他的上面調用方法; 使用 any
類型會致使這個函數能夠接受任何類型的參數,這樣會丟失一些信息;若是咱們傳入一個數字,咱們只知道任何類型的值都有可能被返回
let list:any[] = ['Xcat Liu', 25, { website: 'http://xcatliu.com' }];
let notSure:any = 4
notSure = "maybe a string instead"
notSure = false
複製代碼
void
類型與 any
類型相反他表示沒有任何類型,當有一個函數沒有返回
function warnUser():void {
console.log("This is my waring message")
}
複製代碼
undefined
和null
,它們的自己的類型用處不是很大:Never
類型表示的那些永遠不存在的值類型
as
相信我,我知道本身在幹什麼let someValue:any = "this is a string"
let strLength:number = (<string>someValue).length//「尖括號」語法
let strLength1: number = (someValue as string).length;//一個爲as語法
複製代碼
let myFavoriteNumber:string|number;// 鏈接符 |
myFavoriteNumber = 'seven'
myFavoriteNumber = 7
複製代碼
API
,同時也要考慮可重用性,組件不只可以支持當前的數據類型,同時也能支持將來的數據類型,這在建立大型系統時爲你提供了十分靈活的功能 用泛型來建立可重用的組件;泛型是一種
特殊的變量,只用於表示類型而不是值
function identity<T>(arg:T):T {
return arg;
}
let output = identity<string>("myString")
複製代碼
區別:泛型函數和非泛型函數沒有什麼不一樣,只是有一個類型參數在最前面,像函數聲明同樣
let myIdentity:<T>(arg:T) => T = identity
let myIdentity1:{ <T>(arg:T):T} = identity
複製代碼
可使用帶有調用簽名的對象字面量來定義泛型函數,咱們能夠將對象字面量拿出來做爲一個接口,將一個泛型參數當作整個接口的一個參數,這樣咱們就能清楚的知道使用的具體是哪一個泛型類型
interface GenericIdentityFn {
<T>(arg:T):T
}
function identity<T>(arg:T):T {
return arg
}
let myIdentity:GenericIdentityFn = identity
複製代碼
泛型類看上去和泛型接口差很少,泛型類使用(<>)括起泛型類型,跟在類名後面
class GenericNumber<T> {
zeroValue:T,
add:(x:T,y:T)=>T
}
let myGenericNumber = new GeneriNumber<number>()
複製代碼
類有兩個部分:靜態部分和實例部分,泛型類指的實例部分,因此靜態屬性不能使用這個泛型類型,定義接口來描述約束條件
interface Lengthwise {
length:number
}
function loggingIdentity<T extends Lengthwise>(arg:T):T {
console.log(arg.length)
return arg
}
複製代碼
extends
繼承了一個接口進而對泛型的數據結構進行了限制
TypeScript
核心原則之一是對值所具備的結構進行類型檢查,它是對行爲的抽象,具體行動須要有類去實現,通常接口首字母大寫。通常來說,一個類只能繼承來自另外一個類。有時候不一樣類之間能夠有一些共有的特性,這時候就能夠把特性提取成接口,用
inplements
關鍵字來實現,這個特性大大提升了面向對象的靈活性
可選屬性的好處:可能存在的屬性進行定義,捕獲引用了一個不存在的屬性時的錯誤
一些對象屬性只能在對象剛剛建立的時候修改它的值
interface Point {
readonly x:number;
readonly y:number;
}
複製代碼
TypeScript
具備 ReadonlyArray<T>
類型,它與 Array<T>
類似只是把全部的可變方法去掉了,確保數組建立後不再能被修改
readonly vs const
若是咱們要把他當作一個變量就使用 const
,若爲屬性則使用readonly
1.可使用類型斷言繞過這些檢查(斷言的兩種形式)
let strLength:number = (<string>someValue).length //「尖括號」語法
let strLength1: number = (someValue as string).length //一個爲 `as` 語法
複製代碼
2.使用索引籤,對象賦值給另外一個變量,對象字面量會被特殊對待並且會通過 額外屬性檢查,當將它們賦值給變量或做爲參數傳遞的時候
let squareOptions = { colour: "red", width: 100 }
let mySquare = createSquare(squareOptions)
複製代碼
3.添加字符串索引簽名
interface SquareConfig {
color?:string;
width?:number;
[propName:string]:any
}
複製代碼
接口可以描述 JavaScript
中對象擁有的各類各樣的外形,描述了帶有的普通對象以外,接口也能夠描述成函數類型;他有一個調用簽名,參數列表和返回值類型的函數定義,參數列表裏的每個參數都須要名字和類型,函數的參數名不須要與接口裏定義的名字相匹配,若是你沒有指定參數類型,TypeScript
的類型系統會推斷出參數類型
interface SearchFunc {
(source:string,subString:string):boolean;
}
let MySearch:SearchFunc;
MySearch = function(source:string,subString:string) {
let result = source.search(subString);
return result > -1
}
複製代碼
interface StringArray {
[index:number]:string
}
//let myArray:StringArray = ["Bob",'Fred']
let myArray:StringArray;
myArray = ["Bob",'Fred']
複製代碼
implements
interface ClockInterface {
currentTime: Date;
}
class Clock implements ClockInterface {
currentTime:Date;
constructor(h:number,m:number){}
}
複製代碼
interface Shape {
color:string;
}
interface PenStroke {
penWidth:number;
}
interface Square extends Shape,PenStroke {
sideLength:number
}
let square = <Square>{}
複製代碼
extends
是繼承某個類, 繼承以後可使用父類的方法, 也能夠重寫父類的方法;
implements
是實現多個接口, 接口的方法通常爲空的, 必須重寫才能使用
this
,他表示咱們訪問的是類成員
類(
Class
):定義一件事情的抽象特色,包括他的屬性和方法
對象(
Object
):類的實例,經過new
生成
面向對象(
OOP
)的三大特性:封裝,繼承,多態
封裝(
Encapsulation
): 將對數據的操做細節隱藏起來,只暴露對外的接口,外界端不須要(也不可能)知道細節,就能經過對外提供的接口訪問該對象,同時也保證了外界沒法任意改變對象內部數據
繼承(
Inheritance
):子類繼承父類,子類除了擁有父類的全部特性外,還有一些更具體的特性
多態(
Polymorphism
):由繼承而產生了相關的不一樣類,對同一個方法有不一樣的響應。好比Cat
和Dog
都繼承自Animal
,可是分別實現了本身的eat
方法。此時針對某一個實例,咱們無需瞭解它是Cat
仍是Dog
,就能夠直接調用eat
方法,程序會自動判斷出來應該如何執行eat
存取器(
getter & setter
):用以改變屬性的讀取和賦值行爲
修飾器(
Modifiers
):修飾符是一些關鍵字,用於限定成員或類型的性質
抽象類(
Abstract Class
):抽象類是提供其餘類繼承的基類,抽象類不容許被實例化,抽象類的抽象方法必須在子類中被實現
接口(
Interface
):不一樣類之間公有的屬性和方法,能夠抽象成一個接口,接口能夠被類實現(implements
),一個類只能繼承自另外一個類,可是能夠實現多個接口
class Greeter {
greeting:string;
constructor(message:string) {
this.greeting = message
}
greet() {
return "Hello" + this.greeting
}
}
let greeter = new Greeter("World")
複製代碼
new
構造 Greeter
類的一個實例,調用以前定義的構造函數,建立一個Greeter
類型的新對象,執行構造函數初始化他
經過繼承來擴展示有的類,基類一般被稱做超類(Animal
),派生類常被稱做子類(Dog
)
class Animal {
name: string;
constructor(theName: string) { this.name = theName; }
move(distanceInMeters:number = 0) {
console.log(`Animal moved ${distanceInMeters}`)
}
}
class Dog extends Animal {
constructor(name: string) { super(name); }
bark() {
console.log("woof woof")
}
move(distanceInMeters = 5) {
super.move(distanceInMeters)
}
}
const dog = new Dog()
dog.bark()
dog.move(10)
複製代碼
派生類包含一個構造函數,他必須調用 super()
,他會執行基類函數,在構造器函數裏訪問 this
的屬性前,必定要調用 super()
。這是 TypeScript
強制執行的一條重要規則
在全部 TypeScript
裏,成員都默認爲 public
當成員被標記成
private
時,他就不能在聲明他的外部訪問
protected
和private
修飾符行爲很相似,可是有一點不一樣protected
成員在派生類中仍然能夠訪問。
readonly
關鍵字將屬性設置爲只讀,只讀屬性必須在聲明或者構造函數裏被初始化
TypeScript
使用的是結構性類型系統,當咱們比較兩種不一樣的類型的時候,若是類型成員是兼容的,咱們就認爲他們類型是兼容的
TypeScript
支持經過 getters/setters
來截取對對象成員的訪問
let passcode = 'secret passcode'
class Employee {
private _fullName:string;
get fullName():string {
return this._fullName
}
set fullName(newName:string){
if (passcode && passcode == "secret passcode") {
this._fullName = newName
} else {
console.log("Error: Unauthorized update of employee!");
}
}
}
let employee = new Employee();
employee.fullName = "Bob Smith";
if (employee.fullName) {
alert(employee.fullName);
}
複製代碼
當屬性只存在於類自己上面而不是類實例上,叫作靜態成員標識符 static
做爲其餘派生類的基類使用,他們通常不會直接被實例化,抽象類中的抽象方法不包含具體實現而且必須在派生類中實現。抽象方法的語法和接口方法類似,都只是定義方法簽名,但不包括方法體。抽象類可包含成員的實現細節,必須包含 abstract
關鍵字標識和訪問修飾符
abstract class Animal {
abstract makeSound():void
move():void {
console.log('roaming the earch...')
}
}
複製代碼
類定義會建立兩個東西:類的實例和一個構造函數,類能夠建立類型,因此你可以在容許使用接口的地方使用類
class Point {
x:number;
y:number;
}
interface Point3d extends Point {
z:number
}
let point3d:Point3d = {x:1,y:2,z:3}
複製代碼
JavaScript
中有不少內置對象,它們能夠直接在 TypeScript
中當作定義好了的類型
let b:Boolean = new Boolean(1)
let c:Error = new Error('Error occurred')
let d:Date = new Date()
let r:RegExp = /[a-z]/
複製代碼
DOM
和 BOM
提供的內置對象,在 TypeScript
中會常常用到
暫時就先寫到這裏了,下次繼續,初學者不少不懂得地方,歡迎指正,學習交流
好像天天都在加班,回家老是很晚。促使我學 TypeScript
最主要的緣由是對代碼有着嚴格的要求,將某些未來可能會出現的 bug
扼殺在搖籃裏。在項目開發過程當中,我寫了一個公共的方法用來解析後端傳個人數據格式,突然有一天某個後端給個人數據結構從字符串變成了數組,就那麼一兩個接口的的數據結構變了,大部分的數據結構沒有變。致使頁面報錯,一行一行代碼排除,最後找到公共方法,花了我好長一段時間。那時候我就在想 java
多好呀,直接定義數據類型。避免了我這樣的狀況。後來我知道了 TypeScript
也能夠。慢慢的喜歡上他。對代碼有着嚴格的要求,提早 debug
,最近準備好好學,在忙都要學,可方便了。
在學習 TypeScript
官方文檔的時候,我類比 java
的語法學習,我本身感受語法挺像的。我還總是問個人同事,大家 java
裏面是否是有那個語法 implements
和 extends
, 還請教了她們在 java
它們的區別。個人同事覺得我在學 java
,我回她們說類比學前端
有 TypeScript
資料求推薦,資源共享,看了兩遍官方文檔,之後準備結合項目進行實戰。若是你有相關的開發經驗,想像你學習,交流哈哈,須要一個老司機帶我哈哈