基礎類型
- 布爾值
let isDone: boolean = false
- 數(shù)字
和 JavaScript 一樣,TS里所有數(shù)字都是浮點數(shù),類型是 number。除了支持十進制和十六進制字面量,還支持二進制和八進制字面量。
let decLiteral: number = 6
let hexLiteral: number = 0xf00d
let binaryLiteral: number = 0b1010
let octalLiteral: number = 0o744
- 字符串
let name: string = "bob"
還可以使用模版字符串,它可以定義多行文本和內(nèi)嵌表達式。這種字符串是被反引號包圍,并且以${ expr }這種形式嵌入表達式
let name: string = `Gene`
let sentence: string = `Hello, my name is ${ name }`
- 數(shù)組
有兩種方法定義數(shù)組。第一種,在元素上面接上[],表示由此類型元素組成一個數(shù)組:
let list: number[] = [1, 2, 3]
第二種,使用數(shù)組泛型,Array<元素類型>
let list: Array<number> = [1, 2, 3]
- 元祖 Tuple
元祖類型允許表示一個已知元素數(shù)量和類型的數(shù)組,各元素類型不必相同。比如,你可以定義一對值分別為string和number類型的元祖
// Declare a tuple type
let x: [string, number]
// Initialize it
x = ['hello', 10] // OK
// Initialize it incorrectly
x = [10, 'hello'] // Error
- 枚舉
默認情況下從0開始為元素編號
enum Color {Red, Green, Blue}
let c: Color = Color.Green
我們也可以手動為元素編號
enum Color {Red = 1, Green, Blue}
let colorName: string = Color[2]
console.log(colorName) // 顯示'Green'因為上面代碼里它的值是2
- Any
當我們想要為那些在編程階段還不清楚類型的變量指定一個類型,可以使用any類型來標記這些變量
let notSure: any = 4
notSure = "maybe a string instead"
notSure = false // okay, definitely a boolean
在對現(xiàn)有代碼進行改寫的時候,any類型是十分有用的,可以在上面調(diào)用任意的方法
let notSure: any = 4
notSure.ifItExists() // okay, ifItExists might exist at runtime
notSure.toFixed() // okay, toFixed exists (but the compiler doesn't check)
當你只知道一部分數(shù)據(jù)的類型時,any類型也是有用的。 比如,你有一個數(shù)組,它包含了不同的類型的數(shù)據(jù)
let list: any[] = [1, true, "free"]
list[1] = 100
- Void
某種程度上來說,void類型與any類型相反,它表示沒有任何類型。當一個函數(shù)沒有返回值的時候,你通常會見到其返回值類型是void
function warnUser(): void {
console.log("This is my warning message")
}
聲明一個void類型的變量沒有什么大用,因為你只能賦予undefined和null
- Null 和 Undefined
默認情況下,undefined和null是所有類型的子類型
- Never
never類型表示的是那些用不存在值的類型,never是任何類型的子類型
- Object
object表示非原始類型,也就是除number,string,boolean,symbol,null或undefined之外的類型
變量聲明
- 參考我的另一篇文章:ES 6 的聲明方式
- 解構
數(shù)組解構賦值
let input = [1, 2]
let [first, second] = input
console.log(first) // outputs 1
console.log(second) // outputs 2
以上代碼使用索引
first = input[0]
second = input[1]
用于已聲名的變量:
// swap variables
[first, second] = [second, first]
作用于函數(shù)
let input = [1, 2]
function f([first, second]: [number, number]) {
console.log(first)
console.log(second)
}
f(input)
在數(shù)組中使用...語法創(chuàng)建剩余變量
let [first, ...rest] = [1, 2, 3, 4]
console.log(first) // outputs 1
console.log(rest) // outputs [ 2, 3, 4 ]
當然,也可以忽略尾隨元素
let [first] = [1, 2, 3, 4]
console.log(first) // outputs 1
- 對象解構
let o = {
a: "foo",
b: 12,
c: "bar"
}
let { a, b } = o
上面代碼通過o.a和o.b創(chuàng)建了a和b
可以在對象里使用...語法創(chuàng)建剩余變量
let { a, ...passthrough } = o
let total = passthrough.b + passthrough.c.length
- 屬性命名
let { a: newName1, b: newName2 } = o
方向從左至右,可以像以下代碼一樣理解
let newName1 = o.a
let newName2 = o.b
需要注意的是這里,這里冒號不是指示類型。如果想要指定類型,仍需在后面寫上完整的模式
let {a, b}: {a: string, b: number} = o
- 展開
展開操作符與解構相反
let first = [1, 2]
let second = [3, 4]
let bothPlus = [0, ...first, ...second, 5]
上面代碼令bothPlus的值為[0,1,2,3,4,5]。展開操作創(chuàng)建了first和second的一份淺拷貝,不會被展開操作所改變。
不建議展開對象
接口
TypeScript的核心原則之一是對所具有的結構進行類型檢查。
在TypeScript里,接口的作用就是為了這些類型命名和為你的代碼或第三方代碼訂立契約。
接口是如何工作的:
function printLabel(labelledObj: { label: string }) {
console.log(labelledObj.label)
}
let myObj = { size: 10, label: "Size 10 Object" }
printLabel(myObj);
類型檢查器會查看printLabel的調(diào)用。printLabel有一個參數(shù),并要求這個對象參數(shù)有一個名為label類型為string的屬性。需要注意的是,我們傳入的對象參數(shù)實際上會包含很多屬性,但是編譯器只會檢查那些必須的屬性是否存在,并且其類型是否匹配。
下面用接口描述上面的例子(必須包含一個label屬性且類型為string):
interface LabelledValue {
label: string;
}
function printLabel(labelledObj: LabelledValue) {
console.log(labelledObj.label);
}
let myObj = {size: 10, label: "Size 10 Object"};
printLabel(myObj);
LabelledValue接口就好比一個名字,用來描述上面例子里的要求。它代表了有一個label屬性且類型為string的對象。在這里只關注值的外形。只要傳入對象滿足接口,那么它就是被允許的。
類檢查器不會檢查屬性的順序,只要相應的屬性存在即可。
- 可選屬性
接口里的屬性不全都是必須的。有些是只在某些條件下存在,或者根本不存在。 可選屬性在應用“option bags”模式時很常用,即給函數(shù)傳入的參數(shù)對象中只有部分屬性賦值了。
下面是應用了“option bags“的例子:
interface SquareConfig{
color?: string
width?: number
}
funcrtion createSquare(config:SquareConfig):{color: string; area: number}{
let newSquare = {color: "white"; area: 100}
if(config.color){
newSquare.color = config.color
}
if(config.width){
newSquare.area = config.width * config.width
}
return newSquare
}
let mySquare = createSquare({color: "black"})
帶有可選屬性的接口與普通接口的定義差不多,只是在可選屬性名字定義后面加上一個?符號
可選屬性的好處之一是可以對可能存在的屬性進行預定義,好處之二是可以捕獲引用了不存在的屬性時的錯誤。比如,故意將屬性名字拼錯,就會得到一個錯誤提示。
- 只讀屬性
一些對象屬性只能在對象剛剛創(chuàng)建的時候修改其值??梢栽趯傩悦坝?code>readonly來指定只讀屬性:
interface Point {
readonly x: number
readonly y: number
}
可以通過賦值一個對象字面量來構造一個Point。賦值后,x和y再也不能被改變
let p1: Point = {x:10, y: 20}
p1.x = 5 //error
TypeScript具有Readonly<T>類型,確保數(shù)組創(chuàng)建后再也不能被修改:
let a: number[] = [1,2,3,4]
let ro: ReadonlyArray<number> = a
ro[0] = 12 // error
ro.push(5) // error
ro.length = 100 // error
a = ro // error
上面的最后一行,就算是把整個ReadonlyArray賦值到一個普通數(shù)組也不可以。但是可以用類型斷言重寫:
a = ro as number[]
- 函數(shù)類型
為了使用接口表示函數(shù)類型,需要給接口定義一個調(diào)用簽名。它就像是一個只有參數(shù)列表和返回值類型的函數(shù)定義。參數(shù)列表里的每個參數(shù)都需要名字和類型
interface SearchFunc {
(source: string, subString: string): boolean;
}
下例展示了如何創(chuàng)建一個函數(shù)類型的變量,并將一個同類型的函數(shù)賦值給這個變量
let mySearch: SearchFunc
mySearch = function(source: string, subString: string){
let result = source.search(subString)
return result > -1
}
對于函數(shù)類型的類型檢查來說,函數(shù)的參數(shù)名不需要與接口里定義的名字相匹配:
let mySearch: SearchFunc
mySearch = function(src: string, sub:string){
let result = src.search(sub)
return result > -1
}
持續(xù)更新中。。。