[TypeScript] 编程实践之1: Google的TypeScript代码风格2:基本概念

2 基本概念

本文档的其余部分是TypeScript编程语言的正式规范,旨在作为ECMAScript 2015 Language Specification(特别是ECMA-262标准,第6版)的附件来阅读。 本文档描述了TypeScript所添加的语法,以及TypeScript编译器执行的编译时处理和类型检查,但是由于ECMAScript规范涵盖了该内容,因此它仅极少讨论了程序的运行时行为。

2.1 语法约定

在整个文档中,使用ECMAScript语法的现有约定和生产名称来指定TypeScript语言添加的语法。 在TypeScript增强现有语法产生的地方,就这样指出。 例如:

声明:(已修改)
	…
	接口声明
	类型别名声明
	枚举声明

“(Modified”批注指示已替换现有语法产生式,并且“…”引用原始语法产生式的内容。

与ECMAScript语法相似,如果在语法的产生式的右侧出现短语“ [此处没有LineTerminator]”,则表示如果LineTerminator出现在语法中的输入流中,则表示产生的结果不匹配。 指示位置。

2.2 命名

TypeScript编译器的核心目的是跟踪程序中的命名实体,并根据其指定的含义验证它们的使用。 TypeScript中的名称可以根据上下文以多种方式编写。 具体来说,名称可以写为

  • 一个IdentifierName,
  • 属性名称中的StringLiteral,
  • 属性名称中的NumericLiteral,或者
  • 一个ComputedPropertyName,它表示一个众所周知的符号(2.2.3)。

最常见的是,名称的编写要符合标识符的产生,即不是保留字的任何IdentifierName。

2.2.1 保留字

以下关键字是保留关键字,不能用作标识符:

break             case              catch             class  
const             continue          debugger          default  
delete            do                else              enum  
export            extends           false             finally  
for               function          if                import  
in                instanceof        new               null  
return            super             switch            this  
throw             true              try               typeof  
var               void              while             with

以下关键字不能在严格模式代码中用作标识符,但在其它方面不受限制:

implements        interface         let               package  
private           protected         public            static  
yield

以下关键字不能用作用户定义的类型名称,但不受其他限制:

any               boolean           number            string  
symbol

以下关键字在某些情况下具有特殊含义,但是有效的标识符:

abstract          as                async             await  
constructor       declare           from              get  
is                module            namespace         of  
require           set               type

2.2.2 属性命名

以下是ECMAScript语法的PropertyName产生:

PropertyName:
	LiteralPropertyName
	ComputedPropertyName

LiteralPropertyName:
	标识符名称
	字符串字面量
	数值文学

ComputedPropertyName:
	[AssignmentExpression]

属性名称可以是任何标识符(包括保留字),字符串文字,数字文字或计算出的属性名称。 字符串文字可用于为属性名称提供无效标识符,例如包含空格的名称。 数字文字属性名称等效于字符串文字属性名称,其中包含数字文字的字符串表示形式,如ECMAScript规范中所定义。

2.2.3 计算属性命名

ECMAScript 2015允许对象文字和类使用计算的属性名称声明成员。 计算的属性名称指定一个表达式,该表达式在运行时计算实际的属性名称。 由于最终属性名称在编译时未知,因此TypeScript只能对使用计算的属性名称声明的实体执行有限的检查。 但是,可以在需要PropertyName的任何地方使用计算出的属性名称的子集(称为众所周知的符号),包括类型内的属性名称。 如果计算的属性名称具有以下形式,则它是一个众所周知的符号:

[ Symbol . xxx ]

在众所周知的符号中,点右边的标识符必须表示全局变量’Symbol’类型的原始类型符号的属性,否则会发生错误。

在指定ComputedPropertyName的PropertyName中,除非属性名称出现在对象文字(第4.5节)的属性赋值或非环境类(第8.4节)的属性成员声明中,否则需要计算出的属性名称来表示众所周知的符号 )。

下面是一个接口的示例,该接口使用众所周知的符号名称声明属性:

interface Iterable<T> {  
    [Symbol.iterator](): Iterator<T>;  
}

TODO:更新以处理computed property names with literal expressions

2.3 声明

声明在其关联的声明空间中引入名称。 名称在其声明空间中必须是唯一的,并且可以表示值,类型或命名空间或它们的某种组合。 实际上,一个名称最多可以具有三个不同的含义。 例如:

var X: string;    // Value named X

type X = number;  // Type named X

namespace X {     // Namespace named X  
    type Y = string;  
}

表示值的名称具有关联的类型(第3节),可以在表达式中引用(第4.3节)。 表示类型的名称可以单独在类型引用中使用,也可以在类型引用中的点的右侧使用(第3.8.2节)。 表示命名空间的名称可以在类型引用中点的左侧使用。

当引用具有多种含义的名称时,引用所处的上下文将确定含义。 例如:

var n: X;        // X references type  
var s: X.Y = X;  // First X references namespace, second X references value

在第一行中,X引用类型X,因为它出现在类型位置。在第二行中,第一个X引用命名空间X,因为它出现在类型名称中的点之前,而第二个X引用变量X,因为它出现在表达式中。

声明为其声明的名称引入以下含义:

  • 变量,参数,函数,生成器,成员变量,成员函数,成员访问器或枚举成员声明引入了值的含义。
  • 接口,类型别名或类型参数声明引入了类型含义。
  • 类声明引入了值含义(构造函数)和类型含义(类类型)。
  • 枚举声明引入了值的含义(枚举实例)和类型的含义(枚举类型)。
  • 命名空间声明引入了命名空间含义(类型和命名空间容器),并且,如果实例化命名空间(第10.1节),则引入值含义(命名空间实例)。
  • 导入或导出声明引入了导入或导出实体的含义。

以下是一些声明示例,它们为名称引入了多种含义:

class C {      // Value and type named C  
    x: string;  
}

namespace N {  // Value and namespace named N  
    export var x: string;  
}

声明空间的存在如下:

  • 全局命名空间,每个模块和每个声明的命名空间都为其包含的实体(无论是本地实体还是导出实体)都具有声明空间。
  • 每个模块为其导出的实体都有一个声明空间。模块中的所有导出声明都将占该声明空间。
  • 每个声明的命名空间都有一个用于其导出实体的声明空间。命名空间中的所有导出声明都对此声明空间有所贡献。已声明的命名空间的声明空间与具有相同的根容器和从该根容器开始具有相同的合格名称的其他已声明的命名空间共享。
  • 每个类声明都有一个用于实例成员和类型参数的声明空间,以及一个用于静态成员的声明空间。
  • 每个接口声明都有一个用于成员和类型参数的声明空间。接口的声明空间与其他具有相同根容器和从该根容器开始具有相同限定名称的接口共享。
  • 每个枚举声明都有一个用于其枚举成员的声明空间。一个枚举的声明空间与其他具有相同根容器且从该根容器开始具有相同限定名称的枚举共享。
  • 每个类型别名声明都有一个用于其类型参数的声明空间。
  • 每个类似函数的声明(包括函数声明,构造函数声明,成员函数声明,成员访问器声明,函数表达式和箭头函数)都有一个用于局部变量和类型参数的声明空间。该声明空间包括参数声明,所有局部var和函数声明,以及局部let,const,类,接口,类型别名和枚举声明,这些声明立即出现在函数体内,并且不再嵌套在块中。
  • 每个语句块都有一个声明空间,用于在该块中立即发生的本地let,const,类,接口,类型别名和枚举声明。
  • 每个对象文字都有其属性的声明空间。
  • 每个对象类型文字都有其成员的声明空间。

没有顶级导入或导出声明的源文件中的顶级声明属于全局命名空间。具有一个或多个顶级导入或导出声明的源文件中的顶级声明属于该源文件表示的模块。

实体的容器定义如下:

  • 在命名空间声明中声明的实体的容器就是该命名空间声明。
  • 在模块中声明的实体的容器就是该模块。
  • 在全局命名空间中声明的实体的容器是全局命名空间。
  • 模块的容器是全局命名空间。

实体的根容器定义如下:

  • 非导出实体的根容器是该实体的容器。
  • 导出实体的根容器是实体容器的根容器。

直观地,实体的根容器是可从中访问实体的最外面的模块或命名空间主体。

接口,枚举和命名空间是“开放式”的,这意味着相对于公共根具有相同限定名称的接口,枚举和命名空间声明会自动合并。 有关更多详细信息,请参见第7.2节第9.3节第10.5节

类中的实例成员和静态成员位于单独的声明空间中。 因此,以下内容是允许的:

class C {  
    x: number;          // Instance member  
    static x: string;   // Static member  
}

2.4 范围

名称的范围是程序文本的区域,在该区域内可以引用该名称声明的实体而无需对该名称进行限定。 名称的范围取决于声明名称的上下文。 下面按从最外到最内的顺序列出了上下文:

  • 在全局命名空间中声明的名称的范围是整个程序文本。
  • 在模块中声明的名称范围是该模块的源文件。
  • 在命名空间声明中声明的导出名称的范围是该命名空间声明的主体,以及相对于该根具有相同根和相同限定名称的每个命名空间声明。
  • 在命名空间声明中声明的非导出名称的范围是该命名空间声明的主体。
  • 在类或接口声明中声明的类型参数名称的范围是整个声明,包括约束,extends子句,Implements子句和声明主体,但不包括静态成员声明。
  • 在类型别名声明中声明的类型参数名称的范围是整个类型别名声明。
  • 枚举声明中声明的成员名称的范围是该声明的主体,以及每个相对于该根具有相同根和相同限定名称的枚举声明。
  • 在调用或构造签名中声明的类型参数名称的范围是整个签名声明,包括约束,参数列表和返回类型。如果签名是功能实现的一部分,则范围包括功能主体。
  • 在调用或构造签名中声明的参数名称的范围是签名声明的其余部分。如果签名是带有主体的类函数声明的一部分(包括函数声明,构造函数声明,成员函数声明,成员访问器声明,函数表达式或箭头函数),则范围包括该类函数声明的主体。
  • 在类似函数的声明主体中任何地方声明的局部var或函数名称的范围是该类似函数的声明的主体。
  • 立即在类函数声明的主体内声明的局部let,const,类,接口,类型别名或枚举声明的范围是该类函数声明的主体。
  • 立即在语句块中声明的局部let,const,类,接口,类型别名或枚举声明的范围是该语句块的主体。

作用域可能会重叠,例如通过嵌套命名空间和函数。当两个名称的范围重叠时,具有最内部声明的名称将具有优先权,并且不能或只能通过限定来访问外部名称。

当标识符解析为PrimaryExpression(第4.3节)时,仅考虑作用域中具有值含义的名称,而忽略其他名称。

当标识符解析为TypeName时(第3.8.2节),仅考虑作用域中具有类型含义的名称,而忽略其他名称。

当标识符解析为NamespaceName(第3.8.2节)时,仅考虑作用域中具有命名空间含义的名称,而忽略其他名称。

待办事项:包括用于别名解析的特定规则

请注意,类和接口成员永远不会直接在作用域中,只能通过将点(’.’)运算符应用于类或接口实例来访问它们。这甚至包括构造函数或成员函数中当前实例的成员,可通过将点运算符应用于此成员来访问它们。

正如上述规则所暗示的那样,在命名空间中本地声明的实体在范围上比在相同命名空间的其他命名空间声明中声明的导出实体更近。例如:

var x = 1;  
namespace M {  
    export var x = 2;  
    console.log(x);     // 2  
}  
namespace M {  
    console.log(x);     // 2  
}  
namespace M {  
    var x = 3;  
    console.log(x);     // 3  
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值