TypeScript原始类型与对象类型

这节主要介绍TypeScript的原始类型以及对象类型,主要通过与JavaScript的对比来说明,同时介绍几个相关的TS config配置项。

配置

strictNullChecks

在 TypeScript 的配置文件 tsconfig.json 中,strictNullChecks 是一个用于开启或关闭严格的空值检查的选项。这个选项对于避免在代码中出现空引用错误(如 undefinednull 引用错误)非常有用。

strictNullChecks 设为 true 时,TypeScript 将对变量、属性和参数进行空值检查,确保它们不是 nullundefined,除非明确声明为可以接受这些值。这样有助于减少在运行时因为空引用而导致的错误。

如下所示,当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 相关的类型,如 DocumentHTMLElement 等。

如果你不指定 lib 选项,TypeScript 编译器将默认根据你指定的 target 选项来选择一组默认的库。但在一些情况下,你可能需要手动选择要使用的库,以确保你的代码在目标环境中有望正确运行。

类型

null以及undefined

在Javascript中

  • undefined 通常表示缺少值,由 JavaScript 运行时赋予变量的默认值,或者表示未定义的对象属性。
  • null 通常是开发者显式赋予的值,用于表示变量或对象属性为空。

而在typescript中,null跟undefined都是有意义的具体类型,在没有开启strictNullChecks检查的情况下,这两者会被视为其他类型的子类型 。比如string类型被认为包含了nullundefined类型。

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 中,typeinterface 都用于创建自定义的类型,但它们有一些关键的区别。下面是它们之间的一些主要差异:

语法:

  • interface 使用 interface 关键字来定义。

    typescript 复制代码
    interface Person {
      name: string;
      age: number;
    }
  • type 使用 type 关键字来定义。

    typescript 复制代码
    type Person = {
      name: string;
      age: number;
    };

可合并性(Merging):

  • interface 具有相同名称的两个接口会自动合并。

    typescript 复制代码
    interface Car {
      brand: string;
      speed: number;
    }
    
    interface Car {
      model: string;
    }
    
    // 合并后的 Car 接口
    // { brand: string; speed: number; model: string; }
  • type 具有相同名称的两个类型定义不会自动合并。如果尝试合并两个相同名称的类型,将会产生错误。

继承和实现:

  • interface 可以被类实现(implements)和扩展(extends)。

    typescript 复制代码
    interface Shape {
      draw(): void;
    }
    
    class Circle implements Shape {
      draw() {
        console.log("Drawing a circle");
      }
    }
  • type 不能被类实现或扩展。它通常用于创建复杂的联合类型、交叉类型等。

拓展(Extending):

  • interface 可以使用 extends 关键字来拓展其他接口。

    typescript 复制代码
    interface Person {
      name: string;
      age: number;
    }
    
    interface Employee extends Person {
      jobTitle: string;
    }
  • type 可以使用交叉类型来合并其他类型。

    typescript 复制代码
    type Person = {
      name: string;
      age: number;
    };
    
    type Employee = Person & { jobTitle: string };

总结

  • strictNullChecks配置用于是否检查代码中的null以及undefined,减少运行时由于空值引起的错误;
  • lib 选项用于指定目标环境中可用的 JavaScript 标准库的列表;
  • null以及undefined在typescript中是有意义的类型;
  • void在Javascript中是一元运算符,在TypeScript中是一个特殊的类型,表示函数没有返回值;
  • 在 TypeScript 中,元组(Tuple)类型是一种特殊的数组类型,它允许我们定义一个固定长度和固定类型的数组;
  • typeinterface 都用于创建自定义的类型,但在可合并性、扩展性及继承方面存在区别;

扩展

TypeScript 编译器在寻找类型声明(或类型定义)时会查找一系列默认的位置,以及你在项目中明确指定的位置。以下是 TypeScript 编译器查找类型声明的默认位置:

  1. 内置类型声明: TypeScript 包含许多内置的类型声明,用于描述 JavaScript 中常见的对象、函数等。这些类型声明包含在 TypeScript 安装目录的 lib 文件夹中。
  2. node_modules/@types 目录: 如果你使用 npm 或者 Yarn 安装了一个带有 @types 前缀的包,TypeScript 将在 node_modules/@types 目录中查找类型声明。例如,如果你安装了 lodash 包,那么 TypeScript 将在 node_modules/@types/lodash 目录中查找类型声明。
  3. node_modules 目录: TypeScript 会在 node_modules 目录中查找直接安装的第三方包中的类型声明。如果一个包没有专门的 @types 目录,TypeScript 将尝试从 node_modules 中直接寻找。
  4. tsconfig.json 中的 typeRootstypes 选项: 你可以在 tsconfig.json 文件中配置 typeRootstypes 选项来指定额外的类型声明的搜索路径。typeRoots 是一个字符串数组,表示包含类型声明文件的根目录。types 是一个字符串数组,表示要包含的全局声明文件的相对路径。

以下是一个 tsconfig.json 文件的示例,其中包含了 typeRootstypes 选项:

tsconfig.json 复制代码
{
  "compilerOptions": {
    "typeRoots": ["./typings"],
    "types": ["myCustomTypes"]
  }
}

在这个例子中,TypeScript 将在项目根目录下的 ./typings 文件夹中查找类型声明,并包括名为 myCustomTypes 的全局声明文件。

libtypeRoots 是 TypeScript 配置中两个不同的选项,它们分别用于指定编译器的两个不同方面:JavaScript 标准库的支持和自定义类型声明的搜索路径。

  1. lib 选项: 用于指定目标环境中可用的 JavaScript 标准库的列表。这个选项告诉 TypeScript 编译器应该假定哪些运行时库存在。例如,通过将 "lib": ["es2015", "dom"] 添加到 tsconfig.json 中,你告诉 TypeScript 编译器使用 ECMAScript 2015(ES6)和 DOM 相关的标准库。
  2. typeRootstypes 选项: 用于自定义类型声明文件的搜索路径。typeRoots 是一个字符串数组,指定包含类型声明文件的根目录,而 types 是一个字符串数组,表示要包含的全局声明文件的相对路径。这允许你添加项目特定的或第三方库的类型声明。

虽然两者都与类型相关,但它们的关注点不同:

  • lib 关注于 JavaScript 运行时环境的标准库,即编译器应该假定哪些运行时功能是可用的。
  • typeRootstypes 关注于类型声明文件的位置和自定义类型的添加,即编译器应该在哪里查找并包含类型声明。

在实际项目中,你可能会同时使用这两个选项。例如,你可能会配置 lib 以确定目标 JavaScript 版本和环境,同时使用 typeRootstypes 来添加项目特定的或第三方库的类型声明。

参考: juejin.cn/book/708640...

developer.mozilla.org/zh-CN/docs/...

deepinout.com/typescript/...

geek-docs.com/typescript/...

相关推荐
烛阴13 小时前
前端必会:如何创建一个可随时取消的定时器
前端·javascript·typescript
日月晨曦1 天前
TypeScript:让JavaScript穿上西装革履
前端·typescript
cvpv1 天前
优雅!太优雅!斯巴拉西!怎么让AI写出最优雅的代码
前端·typescript·trae
江拥羡橙1 天前
【基础-判断】HarmonyOS提供了基础的应用加固安全能力,包括混淆、加密和代码签名能力
安全·华为·typescript·harmonyos
烛阴2 天前
TypeScript 接口入门:定义代码的契约与形态
前端·javascript·typescript
Cheney95012 天前
TypeScript 中,! 是 非空断言操作符
前端·vue.js·typescript
掘金安东尼3 天前
TypeScript条件类型与infer构建类型安全的fetch
前端·javascript·typescript
进阶的小木桩3 天前
Vue 3 + Elementui + TypeScript 实现左侧菜单定位右侧内容
vue.js·elementui·typescript
掘金安东尼4 天前
TypeScript 5.9正式发布!!
前端·面试·typescript
IT飞牛4 天前
【MCP开发】Nodejs+Typescript+pnpm+Studio搭建Mcp服务
typescript·mcp