語句(Statements)
這一節講述ts為js語句提供的靜態類型檢測。ts本身並沒有引入任何新的語句結構,但是它擴展了本地聲明的語法,如接口、類型別名和枚舉聲明。
5.1 塊(blocks)
塊擴展了包括本地接口、類型別名和枚舉聲明(ECMAScript 2015 語法中已經存在類)在內的語法。
Declaration: ( Modified )
…
InterfaceDeclaration
TypeAliasDeclaration
EnumDeclaration
聲明:
...
接口聲明
類型別名聲明
枚舉聲明
本地類、接口、類型別名和枚舉聲明都是塊作用域,與”let”和“const”聲明相似。
什么是變量語句?
變量語句包括可選的類型注釋
VariableDeclaration: ( Modified )
SimpleVariableDeclaration
DestructuringVariableDeclaration
變量聲明:
簡單變量聲明
析構變量聲明
變量語句是一個簡單變量聲明或者一個析構變量聲明。
5.1.1 簡單變量聲明(Simple Variable Declaration)
簡單變量聲明引入了一個命名變量和可選的初始化值。
SimpleVariableDeclaration:
BindingIdentifier TypeAnnotationopt Initializeropt
簡單變量聲明:
綁定標識符 類型注釋(可選) 初始化(可選)
簡單變量聲明引入了一個類型“T”,“T”由以下條件決定:
- 如果聲明包含類型注釋,那么“T”就是此類型。
- 否則,如果聲明包含一個初始化表達式,那么“T”就是初始化表達式類型的寬泛格式(widened form)。
- 否則,“T”是“Any”類型。
當一個變量聲明同時指定了一個類型注釋和一個初始化表達式,初始化表達式的類型必須能夠賦給給定的類型注釋。
同一聲明空間中的相同變量名允許具有多個聲明,允許每個聲明與相同類型相關聯。
當一個變量聲明具有類型注釋時,此類型注釋不能用“typeof”操作符來引用已聲明的變量。
下面是一些簡單變量聲明和它們的相關類型。
var a; // any var b: number; // number var c = 1; // number var d = { x: 1, y: "hello" }; // { x: number; y: string; } var e: any = "test"; // any
下面的聲明是允許的,因為變量名為“x”的所有聲明的相關類型都是“Number”類型。
var x = 1; var x: number; if (x == 1) { var x = 2; }
以下幾個變量的類型都是相同的“{ x: number; y: number; }”。
interface Point { x: number; y: number; } var a = { x: 0, y: <number> undefined }; var b: Point = { x: 0, y: undefined }; var c = <Point> { x: 0, y: undefined }; var d: { x: number; y: number; } = { x: 0, y: undefined }; var e = <{ x: number; y: number; }> { x: 0, y: undefined };
5.1.2 析構變量聲明(Destructuring Variable Declaration)
析構變量聲明引入零個或多個命名變量並對其初始化,這些初始化值來源於對象的屬性或數組元素。
DestructuringVariableDeclaration:
BindingPattern TypeAnnotationopt Initializer
析構變量聲明:
綁定模式 類型注釋(可選) 初始化
每一個指定了標識符的綁定特性或者綁定元素都引入了一個變量。變量的類型是與綁定特性或者綁定元素相關類型的寬泛格式。
1、析構變量聲明的相關類型”T”由以下條件決定:
- 如果聲明包含類型注釋,那么“T”就是此類型。
- 否則,如果聲明包含一個初始化表達式,那么“T”就是初始化表達式的類型。
- 否則,“T”是“Any”類型。
2、綁定特性的相關類型“T”由以下條件決定:
- 使直接包含析構變量聲明、綁定特性或綁定元素的相關類型為“S”。
- 如果“S”是“Any”類型:
- 如果綁定特性指定了一個初始化表達式,那么“T”就是初始化表達式的類型。
- 否則,“T”是“Any”類型。
- 使“P”為綁定特性的名稱。
- 如果“S”具有名為“P”的顯性特性,那么“T”就是此特性的類型。
- 否則,如果“S”具有一個數字索引簽名並且“P”是一個數字名稱,那么“T”就是數字索引簽名的類型。
- 否則,如果“S”具有一個字符串索引簽名,那么“T”就是字符串索引簽名的類型。
- 否則,綁定特性不與任何類型相關聯,此時報錯。
3、綁定元素的相關類型“T”由以下條件決定:
- 使直接包含析構變量聲明、綁定特性或綁定元素的相關類型為“S”。
- 如果“S”是“Any”類型:
- 如果綁定元素指定了一個初始化表達式,那么“T”就是初始化表達式的類型。
- 否則,“T”是“Any”類型。
- 如果“S”不是一個類數組類型,那么綁定特性不與任何類型相關聯,此時報錯。
- 如果綁定元素是一個可變元素,“T"是一個具有元素類型”E“的數組類型,”E"是數字索引簽名”S"的類型。
- 否則,如果“S”是一個類元組類型:
- 數組綁定模式中綁定元素的索引是基於零的,使此索引為”N"。
- 如果“S”具有一個數字名為“N"的特性,那么”T"就是特性的類型。
- 否則,綁定元素不與任何類型相關聯,此時報錯。
- 否則,如果“S”具有一個數字索引簽名,那么“T”就是數字索引簽名的類型。
- 否則,綁定特性不與任何類型相關聯,此時報錯。
當一個析構變量聲明、綁定特性或變量元素指定了一個初始化表達式時,此初始化表達式的類型必須能夠賦給相關類型的寬泛形式。
當輸出目標是 ECMAScript 2015或更高時,除非移除可選類型注釋,析構變量聲明在生成的js代碼中保持不變。
當輸出目標是 ECMAScript 3或5時,析構變量聲明被重寫為簡單變量聲明。例如,以下形式的對象析構聲明:
var { x, p: y, q: z = false } = getSomeObject();
被重寫為簡單變量聲明,如下所示:
var _a = getSomeObject(), x = _a.x, y = _a.p, _b = _a.q, z = _b === void 0 ? false : _b;
變量“_a”和“_b”確保賦值表達式只計算一次,“void 0"表達式指代了js值”undefined"。
同樣地、一個如下格式的數組析構聲明
var [x, y, z = 10] = getSomeArray();
被重寫為簡單變量聲明,如下所示:
var _a = getSomeArray(), x = _a[0], y = _a[1], _b = _a[2], z = _b === void 0 ? 10 : _b;
我們將兩種格式的析構聲明組合起來
var { x, p: [y, z = 10] = getSomeArray() } = getSomeObject();
它被重寫為:
var _a = getSomeObject(), x = _a.x, _b = _a.p, _c = _b === void 0 ? getSomeArray() : _b, y = _c[0], _d = _c[1], z = _d === void 0 ? 10 : _d;
5.1.3 隱式類型(Implied Type)
一個變量,參數,綁定特性或綁定元素聲明指定了一個具有隱式類型的綁定模式,這種隱式類型由以下條件決定:
- 如果聲明指定了一個對象綁定模式,那么隱式類型就是一個對象類型,這個對象類型包含了相對於聲明的特性集合。當它的綁定特性聲明指定了一個初始化表達式時,特性是可選的。
- 如果聲明指定了一個無可變元素的數組綁定模式,那么此隱含類型就是具有相關元素的元組類型。
- 如果聲明指定了一個可變元素的數組綁定模式,那么此隱含類型就是一個數組類型,此數組包含"Any“類型的元素。
綁定特性或者綁定元素聲明的隱含類型是:
- 聲明的初始化表達式的類型,否則
- 聲明中指定的綁定模式的隱含類型,否則
- ”Any“類型。
下例中:
function f({ a, b = "hello", c = 1 }) { ... }
函數參數的綁定模式的隱含類型是”{ a: any; b?: string; c?: number; }“。
下例中:
var [a, b, c] = [1, "hello", true];
數組的初始化表達式的類型是綁定模式的隱含類型上下文決定的。因為上下文類型是一個元組類型“[any, any, any]”,結果類型是元組類型“[number, string, boolean]",所以析構聲明為”a","b"和“c"相應地賦予了"number","string"和“boolean"類型。
5.2 常量聲明(Let and Const Declarations)
Let和Const聲明包含可選的類型注釋。
LexicalBinding: ( Modified )
SimpleLexicalBinding
DestructuringLexicalBinding
SimpleLexicalBinding:
BindingIdentifier TypeAnnotationopt Initializeropt
DestructuringLexicalBinding:
BindingPattern TypeAnnotationopt Initializeropt
詞法綁定:
簡單詞法綁定
析構詞法綁定
簡單詞法綁定:
綁定標識符 類型注釋(可選) 初始化(可選)
析構詞法綁定:
綁定模式 類型注釋(可選) 初始化(可選)
5.3 If,Do和While語句
if,do和while表達式可以是任何類型,而不僅僅是布爾類型。
5.4 For語句
for語句中的變量聲明與變量語句中的變量聲明類似。
5.5 For-In語句
在下面格式的for-in語句當中:
for (v in expr) statement
“v”必須是作為“Any”或“String”原始類型引用的表達式。“expr”必須是“Any”類型,對象類型(Object)或者類型參數(type parameter)類型。
在下面格式的“for-in”語句當中:
for (var v in expr) statement
“v”必須是一個無類型注釋的變量聲明,它聲明了一個“Any”類型的變量。“expr”必須是“Any”,對象類型(Object)或者類型參數(type parameter)類型。
5.6 For-Of語句
5.7 Continue語句
continue語句必須直接或間接地嵌套在循環(do、while、for或for-in)語句中。當continue語句包含一個目標標簽時,此標簽必須出現在一個封閉的(但不能越過函數界限)循環語句的標簽組中。
5.8 Break語句
break語句必須直接或間接地嵌套在循環(do、while、for或for-in)或者switch語句中。當break語句包含一個目標標簽時,此標簽必須出現在一個封閉(但不能越過函數界限)語句的標簽組中。
5.9 Return語句
return語句必須包含在函數體內,即return語句不允許存在於命名空間體或全局層中。
無表達式的return語句返回值是“underfined”,它能存在於任何函數體中。
當一個表達式包含return語句,如果函數具有返回類型注釋,那么返回表達式類型由返回類型上下文決定,此類型必須能夠賦給返回類型。否則,如果函數由一個類型“T”上下文決定,那么表達式就由“T”的返回類型上下文決定。
在一個沒有返回類型注釋的函數實現中,返回類型由return語句推斷而得。
下例中:
function f(): (x: string) => number { return s => s.length; }
return語句中的lambda 表達式的類型是有”f“函數的返回類型上下文決定的。
5.10 With語句
5.11 Swith語句
switch語句中的每一個case表達式類型必須與switch表達式類型相匹配。
5.12 Throw語句
throw語句中的表達式可以是任何類型的。
5.13 Try語句
try語句的catch子句引入的變量通常是任何類型的。catch子句不能包含類型注釋。