自动化测试、JavaScript 基础与 TypeScript 编译器指南
自动化测试要点
自动化测试是软件开发中确保代码质量的重要手段。在各类测试中,自动化单元测试相较于集成测试或回归测试更为有效。不过,为了达到最佳的缺陷检测率,综合运用多种测试方法是一个不错的策略。
对于 JavaScript 和 TypeScript 而言,存在众多的测试框架。如果想要缩小选择范围,可以考虑 Jest、Jasmine 和 Mocha。其中,Jest 不仅可以用于编写测试,还能作为文档使用。通过编写规范来驱动实现,能确保当代码行为不正确时测试会失败;而在实现之后再编写测试,并不能保证测试一定会失败。
在开发过程中,不仅要对生产代码进行重构,测试代码同样需要重构。此外,使用简单对象来隔离依赖是一个不错的选择,这比那些可能会使测试与实现过度绑定的复杂工具更为可取。
JavaScript 快速参考
如果你对 JavaScript 还不太熟悉,下面将为你介绍在 TypeScript 程序中会用到的 JavaScript 核心特性。
变量
在 JavaScript 中,变量用于存储应用程序的状态,它可以包含从字符串、数字到对象和函数等任意类型的数据。
变量的声明和赋值可以在同一条语句中完成,也可以分开进行。变量的类型取决于最后一次赋值的值。如果没有赋值,变量的值将为
undefined
。
声明变量时,可以使用
let
和
const
这两个关键字。它们都是块级作用域,与大多数使用花括号的语言类似。使用
let
声明的变量可以在后续代码中重新赋值,而使用
const
声明的变量则不能重新赋值。不过,
const
变量并非不可变,只是变量本身不能被覆盖。在选择关键字时,建议优先使用
const
,当需要重新赋值时再升级为
let
。
let
和
const
都比
var
更受青睐,因为
var
是函数作用域,而非块级作用域。
示例代码如下:
// Variable declaration
let variable;
// Variable assignment
variable = 'A string is assigned';
// Dynamic assignment (changes variable’s type to a number)
variable = 10;
数组
可以将数组存储在变量中。可以使用空字面量
[]
创建一个新的空数组,并使用
array.push
方法添加元素。也可以通过在数组字面量中直接放置值来一次性创建并填充数组。
示例代码如下:
// Creating an empty array and adding values
const myArray = [];
myArray.push(1);
myArray.push(3);
myArray.push(5);
// Adding values using an array literal
const myLiteralArray = [1, 3, 5];
对象
对象可用于表示复杂结构的数据。对象包含的属性类似于变量,可以包含字符串、数字、数组、函数和其他对象。与数组类似,可以使用空对象字面量
{}
创建一个空对象,也可以在对象字面量中放置属性来一次性创建并填充对象。
示例代码如下:
// Objects
const myObject = {};
myObject.title = 'Example Object';
myObject.value = 5;
// Object literals
const myLiteralObject = {
title: 'Example Object',
value: 5
};
在 JavaScript 中,推荐使用字面量语法来创建数组、对象和字符串,而不是使用
new
关键字。
函数
函数可用于在程序中创建可复用的代码块。可以使用函数声明或函数表达式来创建函数。
函数声明示例:
// Function declaration
function myFunction(name) {
return 'Hello ' + name;
}
// 'Hello Steve'
let greeting = myFunction('Steve');
函数表达式示例:
// Function expression
var myFunctionExpression = function (name) {
return 'Hi ' + name;
};
// 'Hi Steve'
greeting = myFunctionExpression('Steve');
使用函数声明创建的函数在解析时就已创建,在其作用域内的任何地方都可以使用;而使用函数表达式创建的函数在运行时才会被计算,只能在其作用域内且调用代码出现在函数表达式之后的地方调用。
条件语句
条件语句可用于在程序中实现逻辑分支,只有当特定条件满足时才会执行相应的代码。
if
语句可以根据自定义条件(结果为
true
或
false
)来分支代码。示例如下:
// If statements
const age = 21;
if (age > 18) {
// Code to execute if age is greater than 18
}
if (age > 40) {
// Code to execute if age is greater than 40
} else if (age > 18) {
// Code to execute if age is greater than 18
// but less than 41
} else {
// Code to execute in all other cases
}
switch
语句适用于根据单个变量的特定值来控制多个分支。示例如下:
// Switch statements
const styles = {
tranditional: 1,
modern: 2,
postModern: 3,
futuristic: 4
};
const style = styles.tranditional;
switch (style) {
case styles.tranditional:
// Code to execute for traditional style
break;
case styles.modern:
// Code to execute for modern style
break;
case styles.postModern:
// Code to execute for post modern style
break;
case styles.futuristic:
// Code to execute for futuristic style
break;
default:
throw new Error('Style not known: ' + style);
}
需要注意的是,
switch
语句与 TypeScript 枚举结合使用效果更佳。
循环
循环用于在程序中重复执行一段代码。JavaScript 中最常见的循环是
for
循环,可用于对数组中的每个元素执行操作。
for
循环示例:
const names = ['Lily', 'Rebecca', 'Debbye', 'Ann'];
for (let i = 0; i < names.length; i++) {
console.log(names[i]);
}
可以使用
for-of
循环简化上述代码,它无需使用变量来跟踪索引,会直接将每次迭代的值赋给一个变量。示例如下:
const names = ['Lily', 'Rebecca', 'Debbye', 'Ann'];
for (let name in names) {
console.log(name);
}
while
循环会重复执行一段代码,直到条件不满足为止。示例如下:
let counter = 10;
while (counter > 0) {
counter--;
console.log(counter);
}
do-while
循环与
while
循环类似,但它至少会执行一次代码,即使条件一开始就不满足。示例如下:
let counter = 0;
do {
counter--;
console.log(counter);
} while (counter > 0);
字符串
虽然大量的字符串操作可能暗示设计存在问题,但 JavaScript 中处理字符串的一些新特性值得了解。
传统字符串可以使用单引号或双引号。反引号字符串可以接受换行符,并允许使用
${}
进行字符串插值,从而可以在字符串中嵌入变量和表达式。示例如下:
const name = 'Jamie';
// Traditional strings
const classicString = 'Line One\n' +
'Line Two\n' +
'Line Three. Hello ' + name + '!';
// Back-ticked strings
const backtickedString = `Line One
Line Two
Line Three. Hello ${name}!`;
// 'Five plus seven is 12.'
const expressionString = `Five plus seven is ${5 + 7}.`;
承诺(Promises)
承诺是 JavaScript 应用程序中快速发展的核心特性,它为协调异步操作提供了一种简单的机制。
使用
fetch
API 从 URL 获取数据的承诺示例:
fetch('/Your/URL/').then(function (response) {
// Response received
if (response.status >= 200 && response.status < 300) {
// We got a success status code
}
}).catch(function (error) {
// Request failed
});
一个承诺包含三个部分:调用一个返回承诺的函数(如
fetch
函数)、成功时调用的
then
结果处理程序以及出错时调用的
catch
结果处理程序。
自定义承诺示例:
let promise = new Promise(function (resolve, reject) {
window.setTimeout(function () {
if (true) {
resolve('Success');
} else {
reject('Failed');
}
}, 1000);
});
promise.then(function (message) {
alert(message);
}).catch(function (error) {
alert(error);
});
TypeScript 编译器
TypeScript 编译器虽然可能隐藏在开发工具之后,但了解其各种编译器选项是很有必要的。目前有超过 70 种不同的编译器标志,下面将介绍一些常见的选项。
编译器位置与运行方式
在 Windows 系统中,TypeScript 编译器
tsc.exe
通常位于
C:\Program Files (x86)\Microsoft SDKs\TypeScript\[Version]\tsc.exe
。要运行编译器,可以在命令行中调用
tsc
并传入程序的根文件名,例如
tsc app.ts
。如果觉得每次输入完整路径很麻烦,可以将 TypeScript 文件夹的路径添加到环境变量中。
也可以在任何操作系统上使用 Node 运行 TypeScript 编译器,需要输入
tsc.js
文件的完整路径(而非
.ts
文件),例如
node tsc.js app.ts
。
获取帮助
如果忘记了编译器的所有选项,可以使用以下命令获取帮助,它们会显示所有可用的编译器标志列表:
-
tsc --help
-
node tsc.js
示例文件
为了说明不同编译器选项之间的关键差异,使用以下示例 TypeScript 代码:
import * as Dependency from './module';
export class Example extends Dependency.BaseClass {
exampleMethod(): number {
return 5;
}
}
// Comment
let example = new Example();
const val = example.exampleMethod();
通过查看该代码生成的 JavaScript 代码,可以了解模块加载和向下编译的差异,向下编译可以将 TypeScript 的最新特性转换为与旧版本 ECMAScript 规范兼容的 JavaScript 代码。
常见标志
-
模块类型(Module Kind)
:
module编译器标志用于生成使用 CommonJS 或 AMD 模块模式加载外部模块的代码。有效的模块类型值包括commonjs和amd。-
UMD(Universal Module Definition)
:
tsc --module UMD app.ts会创建可以在 AMD 和 CommonJS 两种主流模块风格中运行的代码。例如,这样的代码可以在浏览器中由 RequireJS 加载,也可以在服务器上由 Node 加载。此模式的输出比 AMD 或 CommonJS 更冗长,因为它包含用于功能检查以使用正确加载风格的代码。示例如下:
-
UMD(Universal Module Definition)
:
(function (factory) {
if (typeof module === "object" && typeof module.exports === "object") {
var v = factory(require, exports);
if (v !== undefined) module.exports = v;
}
else if (typeof define === "function" && define.amd) {
define(["require", "exports", "./module"], factory);
}
})(function (require, exports) {
"use strict";
exports.__esModule = true;
var Dependency = require("./module");
// Removed for brevity
exports.Example = Example;
// Comment
var example = new Example();
var val = example.exampleMethod();
});
- **AMD**:AMD 模块输出更简洁,因为它不需要进行功能检查。此代码与 RequireJS 和 Dojo Toolkit 等模块加载器兼容。示例如下:
define(["require", "exports", "./module"], function (require, exports, Dependency) {
"use strict";
exports.__esModule = true;
// Removed for brevity
exports.Example = Example;
// Comment
var example = new Example();
var val = example.exampleMethod();
});
- **CommonJS**:CommonJS 模块最著名的实现是 Node,在 MongoDB 和 CouchDB 等中也有使用。示例如下:
"use strict";
exports.__esModule = true;
var Dependency = require("./module");
// Removed for brevity
exports.Example = Example;
// Comment
var example = new Example();
var val = example.exampleMethod();
- **ESNext**:ECMAScript 模块语法与原始 TypeScript 代码最为相似。示例如下:
import * as Dependency from './module';
// Removed for brevity
export { Example };
// Comment
var example = new Example();
var val = example.exampleMethod();
AMD 和 System 模块类型还可以与 `--outFile` 标志一起使用,该标志可以将程序合并为一个 JavaScript 文件。
-
ECMAScript 目标版本(ECMAScript Target Version)
:
target标志允许设置目标 ECMAScript 版本,目前可以针对多个版本的 ECMAScript 规范,包括 ES3、ES5、ES2015、ES2016、ES2017 或使用ESNext针对最新版本。对于大多数语言特性,编译器会将代码向下编译到指定的版本,但少数特性可能不可用。-
ES5 目标
:
tsc --target ES5 app.ts会将代码向下编译到 ECMAScript 5 规范。由于 ES5 不支持const和let关键字,它们会被var关键字替代。在会影响变量作用域的情况下,会生成额外的代码将var关键字封装在一个新的函数作用域中。类会被替换为立即调用的函数表达式(IIFE)。示例如下:
-
ES5 目标
:
import * as Dependency from './module';
var Example = (function (_super) {
__extends(Example, _super);
function Example() {
return _super !== null && _super.apply(this, arguments) || this;
}
Example.prototype.exampleMethod = function () {
return 5;
};
return Example;
}(Dependency.BaseClass));
export { Example };
// Comment
var example = new Example();
var val = example.exampleMethod();
- **ESNext 目标**:当针对支持 TypeScript 中使用的模块加载、类语法和变量声明的最新版本 ECMAScript 规范时,生成的 JavaScript 代码与 TypeScript 代码几乎相同。示例如下:
import * as Dependency from './module';
export class Example extends Dependency.BaseClass {
exampleMethod() {
return 5;
}
}
// Comment
let example = new Example();
const val = example.exampleMethod();
TypeScript 会跟踪 ECMAScript 提案,这意味着最新版本的 TypeScript 和 JavaScript 会非常相似。编译代码的唯一真正区别是类型擦除,因为目前没有计划将类型注解添加到 JavaScript 中。
-
生成声明文件(Generate Declarations)
:
declaration标志会生成一个后缀为.d.ts的额外文件,其中包含代码的环境声明。示例如下:
import * as Dependency from './module';
export declare class Example extends Dependency.BaseClass {
exampleMethod(): number;
}
这个特性在通过 NPM 等包管理器打包程序时非常有用。
-
移除注释(Remove Comments) :
removeComments标志会从输出中删除所有注释,如果源代码中有大量注释,这会使输出文件变小。示例命令:tsc --removeComments true app.ts -
合并输出(Combined Output) :可以使用
out编译器标志将整个 TypeScript 程序合并为一个输出文件,使用该标志时必须指定合并文件的名称。示例命令:tsc --out final.js app.ts。不过,将整个程序压缩为一个输出文件与 TypeScript 编写大型程序的目的相悖,即使是使用 TypeScript 编写小型程序来学习习惯,模块加载也是需要培养的关键习惯之一。 -
代码质量标志(Code Quality Flags) :以下标志可以帮助提高代码质量,并在编译时捕获潜在问题。如果是从头开始编写新程序,启用这些标志并遵循编译器的指导应该很简单。对于现有程序,可以选择启用这些标志,修复编译器发现的一些问题后再关闭,这样可以在多个离散的会话中逐步优化代码,直到最终可以永久启用这些标志。
自动化测试、JavaScript 基础与 TypeScript 编译器指南
代码质量标志详解
代码质量标志在软件开发过程中起着至关重要的作用,它们能够帮助开发者在编译阶段就发现潜在的问题,从而提高代码的可靠性和可维护性。以下为你详细介绍几个常见的代码质量标志及其作用。
--strict
标志
--strict
标志是一个综合性的严格模式开关,它会开启一系列严格的类型检查选项,包括
--strictNullChecks
、
--strictFunctionTypes
、
--strictBindCallApply
、
--strictPropertyInitialization
和
--noImplicitAny
等。开启这个标志后,TypeScript 编译器会对代码进行更严格的检查,减少潜在的运行时错误。
例如,在不开启
--strictNullChecks
时,以下代码可以正常编译:
let name: string;
console.log(name.length); // 不会报错,但运行时可能出错
而开启
--strict
后,编译器会提示
name
可能为
undefined
,需要进行初始化或检查:
let name: string;
console.log(name.length); // 编译错误:'name' is possibly 'undefined'.
使用方法:在命令行中运行
tsc --strict app.ts
即可开启严格模式。
--noImplicitAny
标志
--noImplicitAny
标志会禁止 TypeScript 编译器在没有明确指定类型时默认将变量类型推断为
any
。这有助于提高代码的类型安全性,避免因隐式的
any
类型而导致的潜在错误。
例如,以下代码在不开启
--noImplicitAny
时可以正常编译:
function add(a, b) {
return a + b;
}
开启
--noImplicitAny
后,编译器会提示
a
和
b
缺少类型注解:
function add(a, b) { // 编译错误:Parameter 'a' implicitly has an 'any' type.
return a + b;
}
正确的做法是明确指定参数类型:
function add(a: number, b: number) {
return a + b;
}
使用方法:在命令行中运行
tsc --noImplicitAny app.ts
即可开启该检查。
--noImplicitThis
标志
--noImplicitThis
标志会禁止 TypeScript 编译器在没有明确指定类型时默认将
this
类型推断为
any
。这有助于避免因
this
指向不明确而导致的错误。
例如,以下代码在不开启
--noImplicitThis
时可以正常编译:
const person = {
name: 'John',
greet() {
console.log(`Hello, my name is ${this.name}`);
}
};
const greetFunction = person.greet;
greetFunction(); // 运行时可能出错,this 指向全局对象
开启
--noImplicitThis
后,编译器会提示
this
类型不明确:
const person = {
name: 'John',
greet() {
console.log(`Hello, my name is ${this.name}`); // 编译错误:'this' implicitly has type 'any' because it does not have a type annotation.
}
};
可以通过明确指定
this
类型来解决:
const person = {
name: 'John',
greet(this: { name: string }) {
console.log(`Hello, my name is ${this.name}`);
}
};
const greetFunction = person.greet;
greetFunction.call(person); // 正确调用
使用方法:在命令行中运行
tsc --noImplicitThis app.ts
即可开启该检查。
编译器配置文件
为了方便管理 TypeScript 编译器的选项,可以使用
tsconfig.json
文件。这个文件允许你一次性配置所有的编译器选项,而不需要在每次编译时都在命令行中输入。
创建
tsconfig.json
文件
在项目根目录下创建一个
tsconfig.json
文件,以下是一个简单的示例:
{
"compilerOptions": {
"target": "ES5",
"module": "commonjs",
"strict": true,
"outDir": "./dist",
"rootDir": "./src"
},
"include": ["src/**/*.ts"],
"exclude": ["node_modules"]
}
-
compilerOptions:包含了所有的编译器选项,如目标 ECMAScript 版本、模块类型、是否开启严格模式等。 -
include:指定需要编译的文件或目录,支持通配符。 -
exclude:指定需要排除的文件或目录,通常会排除node_modules目录。
使用
tsconfig.json
进行编译
创建好
tsconfig.json
文件后,在命令行中只需运行
tsc
命令,编译器就会自动读取
tsconfig.json
文件中的配置选项进行编译。
总结
本文详细介绍了自动化测试的要点、JavaScript 的核心特性以及 TypeScript 编译器的常见选项。自动化测试是保证代码质量的重要手段,综合运用多种测试方法可以提高缺陷检测率。JavaScript 作为 TypeScript 的基础,其变量、数组、对象、函数、条件语句、循环、字符串和承诺等特性在 TypeScript 程序中经常使用。TypeScript 编译器提供了丰富的选项,通过合理配置这些选项,可以实现不同的模块加载方式、向下编译到不同的 ECMAScript 版本、生成声明文件、移除注释和合并输出等功能。同时,使用代码质量标志可以帮助开发者提高代码的质量,避免潜在的错误。最后,通过
tsconfig.json
文件可以方便地管理编译器选项,提高开发效率。
在实际开发中,建议开发者根据项目的需求和特点,选择合适的测试框架和编译器选项,养成良好的编码习惯,不断提高代码的质量和可维护性。
流程图:TypeScript 编译流程
graph LR
A[编写 TypeScript 代码] --> B[配置 tsc 选项或使用 tsconfig.json]
B --> C{选择编译器标志}
C -->|模块类型| D1(UMD/AMD/CommonJS/ESNext)
C -->|目标版本| D2(ES3/ES5/ES2015/ES2016/ES2017/ESNext)
C -->|其他标志| D3(生成声明/移除注释/合并输出/代码质量检查)
D1 --> E[编译生成 JavaScript 代码]
D2 --> E
D3 --> E
E --> F[部署或运行 JavaScript 代码]
表格:常见编译器标志总结
| 标志名称 | 作用 | 示例命令 |
|---|---|---|
--module
| 指定模块类型 |
tsc --module UMD app.ts
|
--target
| 设置目标 ECMAScript 版本 |
tsc --target ES5 app.ts
|
--declaration
| 生成声明文件 |
tsc --declaration app.ts
|
--removeComments
| 移除输出文件中的注释 |
tsc --removeComments true app.ts
|
--out
| 合并输出为一个文件 |
tsc --out final.js app.ts
|
--strict
| 开启严格类型检查 |
tsc --strict app.ts
|
--noImplicitAny
|
禁止隐式的
any
类型
|
tsc --noImplicitAny app.ts
|
--noImplicitThis
|
禁止隐式的
this
类型
|
tsc --noImplicitThis app.ts
|
超级会员免费看
6

被折叠的 条评论
为什么被折叠?



