这节主要介绍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
来添加项目特定的或第三方库的类型声明。