[TypeScript] 编程实践之1: Google的TypeScript代码风格5:语句

5 语句

本章介绍TypeScript为JavaScript语句提供的静态类型检查。 TypeScript本身未引入任何新的语句构造,但确实扩展了本地声明的语法,以包括接口,类型别名和枚举声明。

5.1 块

块被扩展为包括本地接口,类型别名和枚举声明(ECMAScript 2015语法已包含类)。

Declaration: ( Modified )
	…
	InterfaceDeclaration
	TypeAliasDeclaration
	EnumDeclaration

局部类,接口,类型别名和枚举声明是块范围的,类似于let和const声明。

5.2 变量语句

变量语句被扩展为包括可选的类型注释。

VariableDeclaration: ( Modified )
	SimpleVariableDeclaration
	DestructuringVariableDeclaration

变量声明可以是简单的变量声明,也可以是解构变量声明。

5.2.1 简单变量声明

一个简单的变量声明引入了一个命名变量,并可以选择为其分配初始值。

SimpleVariableDeclaration:
	BindingIdentifier TypeAnnotationopt Initializeropt

由简单变量声明引入的变量的类型T如下确定:

  • 如果声明包含类型注释,则T为该类型。
  • 否则,如果声明包含初始化程序表达式,则T是初始化程序表达式类型的扩展形式(第3.12节)。
  • 否则,T为Any类型。

当变量声明同时指定类型注释和初始化程序表达式时,要求初始化程序表达式的类型可分配给类型注释中给定的类型(第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 };

5.2.2 析构变量声明

解构变量声明引入了零个或多个命名变量,并使用从对象或数组元素的属性中提取的值对其进行初始化。

DestructuringVariableDeclaration:
	BindingPattern TypeAnnotation_{opt} Initializer

每个指定标识符的绑定属性或元素都通过该名称引入一个变量。变量的类型是与绑定属性或元素关联的类型的扩展形式(第3.12节),如下所示。

TODO:将迭代器分解为数组的文档。

与解构变量声明关联的类型T如下确定:

  • 如果声明包含类型注释,则T为该类型。
  • 否则,如果声明包含初始化程序表达式,则T是该初始化程序表达式的类型。
  • 否则,T为Any类型。

与绑定属性关联的类型T如下确定:

  • 令S为与立即包含的解构变量声明,绑定属性或绑定元素关联的类型。
  • 如果S是Any类型:
    • 如果绑定属性指定了初始化程序表达式,则T是该初始化程序表达式的类型。
    • 否则,T为Any类型。
  • 令P为绑定属性中指定的属性名称。
  • 如果S具有名称为P的外观属性,则T是该属性的类型。
  • 否则,如果S具有数字索引签名,而P是数字名称,则T是数字索引签名的类型。
  • 否则,如果S具有字符串索引签名,则T是字符串索引签名的类型。
  • 否则,没有任何类型与绑定属性相关联,并且会发生错误。

与绑定元素关联的类型T的确定如下:

  • 令S为与立即包含的解构变量声明,绑定属性或绑定元素关联的类型。
  • 如果S是Any类型:
    • 如果绑定元素指定初始化程序表达式,则T是该初始化程序表达式的类型。
    • 否则,T为Any类型。
  • 如果S不是类似数组的类型(第3.3.2节),则没有任何类型与绑定属性相关联,并且会发生错误。
  • 如果绑定元素是rest元素,则T是元素类型为E的数组类型,其中E是S的数字索引签名的类型。
  • 否则,如果S是类似元组的类型(第3.3.3节):
    • 令N为数组绑定模式中绑定元素的从零开始的索引。
    • 如果S具有数字名称N的属性,则T是该属性的类型。
    • 否则,没有任何类型与绑定元素相关联,并且会发生错误。
  • 否则,如果S具有数字索引签名,则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;

5.2.3 implied类型

指定绑定模式的变量,参数,绑定属性或绑定元素声明具有隐式类型,其确定方式如下:

  • 如果声明指定了对象绑定模式,则隐含类型是具有一组与指定的绑定属性声明相对应的属性的对象类型。每个属性的类型都是其绑定属性声明所隐含的类型,并且当其绑定属性声明指定初始化程序表达式时,该属性是可选的。
  • 如果声明指定的数组绑定模式不包含rest元素,则隐含类型为元组类型,其元素与指定的绑定元素声明相对应。每个元素的类型都是其绑定元素声明所隐含的类型。
  • 如果声明指定带有rest元素的数组绑定模式,则隐含类型是元素类型为Any的数组类型。

绑定属性或绑定元素声明的隐式类型为

  • 声明的初始值设定项表达式的类型(如果有),否则
  • 声明中指定的绑定模式的隐式类型(如果有),否则
  • 类型Any。

在这个例子中

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分别。

5.3 let和const声明

将let和const声明扩展为包括可选的类型注释。

LexicalBinding: ( Modified )
	SimpleLexicalBinding
	DestructuringLexicalBinding

SimpleLexicalBinding:
	BindingIdentifier TypeAnnotationopt Initializeropt

DestructuringLexicalBinding:
	BindingPattern TypeAnnotationopt Initializeropt

TODO:文档作用域以及let和const的支持

5.4 If,Do和While语句

控制“ if”,“ do”和“ while”语句的表达式可以是任何类型(而不仅仅是布尔类型)。

5.5 for语句

“ for”语句中的变量声明以与变量语句中的变量声明相同的方式扩展(第5.2节)。

5.6 for-in语句

在表格的“ for-in”声明中

for (v in expr) statement

v必须是分类为类型Any或String基本类型的引用的表达式,而expr必须是类型Any,对象类型或类型参数类型的表达式。

在表格的“ for-in”声明中

for (var v in expr) statement

v必须是没有类型注释的变量声明,该类型声明必须声明Any类型的变量,而expr必须是Any类型的表达式,对象类型或类型参数类型。

5.7 For-of语句

TODO:关于for…of的文档。

5.8 Continue语句

“ continue”语句需要在迭代(“ do”,“ while”,“ for”或“ for-in”)语句内直接或间接嵌套(但不能跨越函数边界)。 当“继续”语句包含目标标签时,该目标标签必须出现在封闭的(但不跨越函数边界)迭代语句的标签集中。

5.9 Break语句

“ break”语句需要在迭代(“ do”,“ while”,“ for”或“ for-in”)或“ switch”语句中直接或间接嵌套(但不能跨越函数边界) 。 当“ break”语句包含目标标签时,该目标标签必须出现在封闭(但不跨越功能边界)语句的标签集中。

5.10 Return语句

'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”。

5.11 With语句

与ECMAScript 5的严格模式一样,在TypeScript中使用’with’语句是一个错误。 此外,在’with’语句的主体内,TypeScript认为表达式(第4.3节)中出现的每个标识符均为Any类型,无论其声明的类型如何。 因为“ with”语句在静态已知的标识符之前将一组静态未知的标识符放在范围内,所以不可能为任何标识符有意义地分配静态类型。

5.12 Switch语句

在’switch’语句中,每个’case’表达式必须具有可与’switch’表达式的类型(第3.11.4节)相对应的类型。

5.13 Throw语句

“ throw”语句中指定的表达式可以是任何类型。

5.14 Try语句

由“ try”语句的“ catch”子句引入的变量始终为Any类型。 在’catch’子句中不能包含类型注释。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值