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/...

相关推荐
一介俗子22 分钟前
TypeScript 中 extends 关键字
typescript
mez_Blog2 小时前
个人小结(2.0)
前端·javascript·vue.js·学习·typescript
QGC二次开发4 小时前
Vue3 : Pinia的性质与作用
前端·javascript·vue.js·typescript·前端框架·vue
2301_801074157 小时前
TypeScript异常处理
前端·javascript·typescript
下雪天的夏风9 小时前
TS - tsconfig.json 和 tsconfig.node.json 的关系,如何在TS 中使用 JS 不报错
前端·javascript·typescript
天下无贼!1 天前
2024年最新版TypeScript学习笔记——泛型、接口、枚举、自定义类型等知识点
前端·javascript·vue.js·笔记·学习·typescript·html
Jorah3 天前
1. TypeScript基本语法
javascript·ubuntu·typescript
小白小白从不日白4 天前
TS axios封装
前端·typescript
aimmon4 天前
Superset二次开发之源码DependencyList.tsx 分析
前端·typescript·二次开发·bi·superset
下雪天的夏风5 天前
Vant 按需引入导致 Typescript,eslint 报错问题
前端·typescript·eslint