这节主要介绍TypeScript的原始类型以及对象类型,主要通过与JavaScript的对比来说明,同时介绍几个相关的TS config配置项。
配置
strictNullChecks
在 TypeScript 的配置文件 tsconfig.json 中,strictNullChecks 是一个用于开启或关闭严格的空值检查的选项。这个选项对于避免在代码中出现空引用错误(如 undefined 或 null 引用错误)非常有用。
当 strictNullChecks 设为 true 时,TypeScript 将对变量、属性和参数进行空值检查,确保它们不是 null 或 undefined,除非明确声明为可以接受这些值。这样有助于减少在运行时因为空引用而导致的错误。
如下所示,当strictNullChecks以及strict都配置为true时,则需要使用条件判断、类型断言或者非空断言操作符(!)来告诉typescript,在某个点上一个值不为null或者undefined。
typescript
let myVar: string | null = getSomeStringOrNull();
// 使用条件判断来避免空引用错误
if (myVar !== null) {
// 在这里 TypeScript 知道 myVar 不为 null
console.log(myVar.length);
}
// 使用类型断言
let length: number = (myVar as string).length;
// 使用非空断言操作符
let anotherLength: number = myVar!.length;
lib
在 TypeScript 的配置文件 tsconfig.json 中,lib 选项用于指定目标环境中可用的 JavaScript 标准库的列表。这个选项允许你明确地选择 TypeScript 编译器要假定存在的运行时库。用来指定TypeScript编译器所能访问的类型声明文件。
tsconfig.json
{
"compilerOptions": {
"target": "es5",
"lib": ["es2015", "dom"]
}
}
在这个例子中,lib 选项指定了两个库:"es2015" 和 "dom"。
"es2015"表示使用 ECMAScript 2015(ES6)中引入的特性。这会让 TypeScript 编译器知道你可以使用 ES6 中的语法和功能。"dom"表示使用 DOM 相关的类型声明。这会让 TypeScript 编译器知道你可以在代码中使用 DOM 相关的类型,如Document、HTMLElement等。
如果你不指定 lib 选项,TypeScript 编译器将默认根据你指定的 target 选项来选择一组默认的库。但在一些情况下,你可能需要手动选择要使用的库,以确保你的代码在目标环境中有望正确运行。
类型
null以及undefined
在Javascript中
undefined通常表示缺少值,由 JavaScript 运行时赋予变量的默认值,或者表示未定义的对象属性。null通常是开发者显式赋予的值,用于表示变量或对象属性为空。
而在typescript中,null跟undefined都是有意义的具体类型,在没有开启strictNullChecks检查的情况下,这两者会被视为其他类型的子类型 。比如string类型被认为包含了null与undefined类型。
typescript
const str1: null = null;
const str2: undefined = undefined;
const str3: string = null; // 仅在关闭 strictNullChecks 时成立,下同
const str4: string = undefined;
void
在Javascript中,void 运算符 对给定的表达式进行求值,然后返回undefined。通常用于创建不产生任何效果的超链接,避免页面跳转。
javascript
<a href="javascript:void(document.body.style.backgroundColor='green');">
点击这个链接会让页面背景变成绿色。
</a>
而在 TypeScript 中,void 是一个特殊的类型,表示函数没有返回值。当一个函数声明返回类型为 void 时,它表示该函数不会返回任何值,或者说返回的值是 undefined。
函数的 void 返回类型:
typescript
function exampleFunction() {
console.log("This function doesn't return anything.");
}
function exampleFunction1() {
console.log("This function doesn't return anything.");
return
}
function exampleFunction1() {
console.log("This function doesn't return anything.");
return undefined
}
在上面的例子中,三个函数返回的值都是undefined,返回值的类型都会被推导成void。
变量 void 的类型 : 在 TypeScript 中,一般不需要显式地声明变量为 void 类型,因为大多数情况下,变量会被推断为 undefined 或其他具体类型。然而,可以使用 void 类型来显式表示一个变量没有返回值。
typescript
let noValue: void = undefined;
let anotherNoValue: void = null; // 也是合法的,但不太常见
元祖类型
在 TypeScript 中,元组(Tuple)类型是一种特殊的数组类型,它允许我们定义一个固定长度和固定类型的数组。与普通数组不同,元组中的每个位置可以有不同的数据类型。 以下是元组类型的基本形式:
typescript
let myTuple: [number, string, boolean];
在这个例子中,myTuple 是一个元组,它包含三个元素,分别是一个数字、一个字符串和一个布尔值,且元素的顺序是固定的。
创建元组 :可以使用方括号 [] 来创建一个元组,并指定每个元素的类型:
typescript
let person: [string, number] = ["Aaron", 33];
这个元组表示一个人的信息,包含姓名和年龄。为了便于代码阅读,可以使用具名元祖:
typescript
let person: [name:string, age:number] = ["Aaron", 33];
访问元组元素:跟数组一样,可以使用索引来访问元组中的元素。索引从 0 开始。
typescript
let name: string = person[0];
let age: number = person[1];
let temp = person[2] //会提示越界访问
type 与 interface
在 TypeScript 中,type 和 interface 都用于创建自定义的类型,但它们有一些关键的区别。下面是它们之间的一些主要差异:
语法:
-
interface: 使用interface关键字来定义。typescriptinterface Person { name: string; age: number; } -
type: 使用type关键字来定义。typescripttype Person = { name: string; age: number; };
可合并性(Merging):
-
interface: 具有相同名称的两个接口会自动合并。typescriptinterface Car { brand: string; speed: number; } interface Car { model: string; } // 合并后的 Car 接口 // { brand: string; speed: number; model: string; } -
type: 具有相同名称的两个类型定义不会自动合并。如果尝试合并两个相同名称的类型,将会产生错误。
继承和实现:
-
interface: 可以被类实现(implements)和扩展(extends)。typescriptinterface Shape { draw(): void; } class Circle implements Shape { draw() { console.log("Drawing a circle"); } } -
type: 不能被类实现或扩展。它通常用于创建复杂的联合类型、交叉类型等。
拓展(Extending):
-
interface: 可以使用extends关键字来拓展其他接口。typescriptinterface Person { name: string; age: number; } interface Employee extends Person { jobTitle: string; } -
type: 可以使用交叉类型来合并其他类型。typescripttype Person = { name: string; age: number; }; type Employee = Person & { jobTitle: string };
总结
strictNullChecks配置用于是否检查代码中的null以及undefined,减少运行时由于空值引起的错误;lib选项用于指定目标环境中可用的 JavaScript 标准库的列表;null以及undefined在typescript中是有意义的类型;void在Javascript中是一元运算符,在TypeScript中是一个特殊的类型,表示函数没有返回值;- 在 TypeScript 中,元组(Tuple)类型是一种特殊的数组类型,它允许我们定义一个固定长度和固定类型的数组;
type和interface都用于创建自定义的类型,但在可合并性、扩展性及继承方面存在区别;
扩展
TypeScript 编译器在寻找类型声明(或类型定义)时会查找一系列默认的位置,以及你在项目中明确指定的位置。以下是 TypeScript 编译器查找类型声明的默认位置:
- 内置类型声明: TypeScript 包含许多内置的类型声明,用于描述 JavaScript 中常见的对象、函数等。这些类型声明包含在 TypeScript 安装目录的
lib文件夹中。 node_modules/@types目录: 如果你使用 npm 或者 Yarn 安装了一个带有@types前缀的包,TypeScript 将在node_modules/@types目录中查找类型声明。例如,如果你安装了lodash包,那么 TypeScript 将在node_modules/@types/lodash目录中查找类型声明。node_modules目录: TypeScript 会在node_modules目录中查找直接安装的第三方包中的类型声明。如果一个包没有专门的@types目录,TypeScript 将尝试从node_modules中直接寻找。tsconfig.json中的typeRoots和types选项: 你可以在tsconfig.json文件中配置typeRoots和types选项来指定额外的类型声明的搜索路径。typeRoots是一个字符串数组,表示包含类型声明文件的根目录。types是一个字符串数组,表示要包含的全局声明文件的相对路径。
以下是一个 tsconfig.json 文件的示例,其中包含了 typeRoots 和 types 选项:
tsconfig.json
{
"compilerOptions": {
"typeRoots": ["./typings"],
"types": ["myCustomTypes"]
}
}
在这个例子中,TypeScript 将在项目根目录下的 ./typings 文件夹中查找类型声明,并包括名为 myCustomTypes 的全局声明文件。
lib 和 typeRoots 是 TypeScript 配置中两个不同的选项,它们分别用于指定编译器的两个不同方面:JavaScript 标准库的支持和自定义类型声明的搜索路径。
lib选项: 用于指定目标环境中可用的 JavaScript 标准库的列表。这个选项告诉 TypeScript 编译器应该假定哪些运行时库存在。例如,通过将"lib": ["es2015", "dom"]添加到tsconfig.json中,你告诉 TypeScript 编译器使用 ECMAScript 2015(ES6)和 DOM 相关的标准库。typeRoots和types选项: 用于自定义类型声明文件的搜索路径。typeRoots是一个字符串数组,指定包含类型声明文件的根目录,而types是一个字符串数组,表示要包含的全局声明文件的相对路径。这允许你添加项目特定的或第三方库的类型声明。
虽然两者都与类型相关,但它们的关注点不同:
lib关注于 JavaScript 运行时环境的标准库,即编译器应该假定哪些运行时功能是可用的。typeRoots和types关注于类型声明文件的位置和自定义类型的添加,即编译器应该在哪里查找并包含类型声明。
在实际项目中,你可能会同时使用这两个选项。例如,你可能会配置 lib 以确定目标 JavaScript 版本和环境,同时使用 typeRoots 和 types 来添加项目特定的或第三方库的类型声明。