本章介绍TypeScript为JavaScript语句提供的静态类型检查。 TypeScript本身未引入任何新的语句构造,但确实扩展了本地声明的语法,以包括接口,类型别名和枚举声明。
块被扩展为包括本地接口,类型别名和枚举声明(ECMAScript 2015语法已包含类)。
Declaration: ( Modified )
…
InterfaceDeclaration
TypeAliasDeclaration
EnumDeclaration
局部类,接口,类型别名和枚举声明是块范围的,类似于let和const声明。
变量语句被扩展为包括可选的类型注释。
VariableDeclaration: ( Modified )
SimpleVariableDeclaration
DestructuringVariableDeclaration
变量声明可以是简单的变量声明,也可以是解构变量声明。
一个简单的变量声明引入了一个命名变量,并可以选择为其分配初始值。
SimpleVariableDeclaration:
BindingIdentifier TypeAnnotationopt Initializeropt
由简单变量声明引入的变量的类型T如下确定:
当变量声明同时指定类型注释和初始化程序表达式时,要求初始化程序表达式的类型可分配给类型注释中给定的类型(第3.11.4节)。
允许在同一声明空间中针对同一变量名称进行多个声明,前提是每个声明将同一类型与变量关联。
当变量声明具有类型注释时,使用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)与’x’关联。
var x = 1;
var x: number;
if (x == 1) {
var x = 2;
}
在以下示例中,所有五个变量都属于同一类型,’{x:number; y:数字; }’。
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 };
解构变量声明引入了零个或多个命名变量,并使用从对象或数组元素的属性中提取的值对其进行初始化。
DestructuringVariableDeclaration:
BindingPattern TypeAnnotation_{opt} Initializer
每个指定标识符的绑定属性或元素都通过该名称引入一个变量。变量的类型是与绑定属性或元素关联的类型的扩展形式(第3.12节),如下所示。
TODO:将迭代器分解为数组的文档。
与解构变量声明关联的类型T如下确定:
与绑定属性关联的类型T如下确定:
与绑定元素关联的类型T的确定如下:
当解构变量声明,绑定属性或绑定元素指定了初始化程序表达式时,要求将初始化程序表达式的类型分配给与解构变量声明,绑定属性或绑定元素相关联的类型的扩展形式。
TODO:更新规则以反映使用文字初始化程序改进对销毁的检查。
当输出目标是ECMAScript 2015或更高版本时,除了删除可选的类型注释之外,解构变量声明在生成的JavaScript代码中保持不变。
当输出目标是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’只是表示JavaScript值’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;
指定绑定模式的变量,参数,绑定属性或绑定元素声明具有隐式类型,其确定方式如下:
绑定属性或绑定元素声明的隐式类型为
在这个例子中
function f({ a, b = "hello", c = 1 }) { ... }
函数参数中绑定模式的隐式类型为’{a:any; b ?:字符串; c ?:数字; }’。 由于参数没有类型注释,因此它将成为参数的类型。
在这个例子中
var [a, b, c] = [1, "hello", true];
数组字面量初始值设定项表达式是由绑定模式的隐式类型在上下文中键入的,特别是元组类型’[any,any,any]’。 因为上下文类型是元组类型,所以数组文字的结果类型是元组类型’[number,string,boolean]’,因此解构声明将类型number,string和boolean赋予a,b和 c分别。
将let和const声明扩展为包括可选的类型注释。
LexicalBinding: ( Modified )
SimpleLexicalBinding
DestructuringLexicalBinding
SimpleLexicalBinding:
BindingIdentifier TypeAnnotationopt Initializeropt
DestructuringLexicalBinding:
BindingPattern TypeAnnotationopt Initializeropt
TODO:文档作用域以及let和const的支持。
控制“ if”,“ do”和“ while”语句的表达式可以是任何类型(而不仅仅是布尔类型)。
“ for”语句中的变量声明以与变量语句中的变量声明相同的方式扩展(第5.2节)。
在表格的“ for-in”声明中
for (v in expr) statement
v必须是分类为类型Any或String基本类型的引用的表达式,而expr必须是类型Any,对象类型或类型参数类型的表达式。
在表格的“ for-in”声明中
for (var v in expr) statement
v必须是没有类型注释的变量声明,该类型声明必须声明Any类型的变量,而expr必须是Any类型的表达式,对象类型或类型参数类型。
TODO:关于for…of的文档。
“ continue”语句需要在迭代(“ do”,“ while”,“ for”或“ for-in”)语句内直接或间接嵌套(但不能跨越函数边界)。 当“继续”语句包含目标标签时,该目标标签必须出现在封闭的(但不跨越函数边界)迭代语句的标签集中。
“ break”语句需要在迭代(“ do”,“ while”,“ for”或“ for-in”)或“ switch”语句中直接或间接嵌套(但不能跨越函数边界) 。 当“ break”语句包含目标标签时,该目标标签必须出现在封闭(但不跨越功能边界)语句的标签集中。
'return’语句出现在函数体之外是错误的。 具体来说,在全局级别或命名空间主体中不允许使用“ return”语句。
不带表达式的’return’语句返回值’undefined’,并且在任何函数的主体中允许该值,而与函数的返回类型无关。
当“ return”语句包含表达式时,如果包含函数包含返回类型注释,则该返回表达式由该返回类型在上下文中键入(第4.23节),并且必须具有可分配给该返回类型的类型。 否则,如果包含函数的上下文类型为T,则Expr上下文类型为T的返回类型。
在没有返回类型注释的函数实现中,返回类型是从函数主体中的“ return”语句中推断出来的,如第6.3节所述。
在这个例子中
function f(): (x: string) => number {
return s => s.length;
}
“ return”语句中的箭头表达式在上下文中由“ f”的返回类型键入,因此将“ string”类型赋予“ s”。
与ECMAScript 5的严格模式一样,在TypeScript中使用’with’语句是一个错误。 此外,在’with’语句的主体内,TypeScript认为表达式(第4.3节)中出现的每个标识符均为Any类型,无论其声明的类型如何。 因为“ with”语句在静态已知的标识符之前将一组静态未知的标识符放在范围内,所以不可能为任何标识符有意义地分配静态类型。
在’switch’语句中,每个’case’表达式必须具有可与’switch’表达式的类型(第3.11.4节)相对应的类型。
“ throw”语句中指定的表达式可以是任何类型。
由“ try”语句的“ catch”子句引入的变量始终为Any类型。 在’catch’子句中不能包含类型注释。