TypeScript从零开始(三):基础类型下

前言

Hello,大家好,我是三棵杨树~

欢迎阅读 TypeScript 从零开始 系列文章第三篇!在上一篇文章中,我们深入讲解了 TypeScript 中的基础类型,包括字符串、数字、布尔值、数组、对象、联合类型和类型别名等。此外,我们还了解了any类型的使用及其潜在风险。

在本篇文章中,我们将继续深入 TypeScript 的基础类型,涵盖接口(Interface)、nullundefined 类型、空值类型、类型断言、字面量类型、类型注解与推断,以及类型收窄等内容。通过学习这些内容,您将进一步掌握 TypeScript 的类型系统,并提升代码的安全性和可维护性。

让我们开始我们的 TS 学习之旅吧!

接口

在上一篇我们知道了如何使用类型别名,这里我们介绍命名对象类型的另外一种方式:接口

typescript 复制代码
interface User {
  name: string;
  age?: number;
}

const userOne: User = {
  name: '张三',
  age: 25,
};

const userTwo: User = {
  name: '李四',
};

类型别名和接口非常相似,在大多数情况下你可以在它们之间自由选择。 几乎所有的 interface 功能都可以在 type 中使用,接下来我们来看看两者的区别。

例如我们现在扩展类型上的属性

typescript 复制代码
// interface
interface User {
  name: string;
  age?: number;
}

interface Student extends User {
  school: string;
}

const userOne: Student = {
  name: '张三',
  age: 25,
  school: 'A大学',
};

const userTwo: Student = {
  name: '李四',
  school: 'B大学',
};

// type 使用 & 交叉类型
type User = {
  name: string;
  age?: number;
};

type Student = User & {
  school: string;
};

const userOne: Student = {
  name: '张三',
  age: 25,
  school: 'A大学',
};

const userTwo: Student = {
  name: '李四',
  school: 'B大学',
};

使用 interface,我们可以通过继承来扩展类型,可以很方便的定义新的类型。如果使用 type,我们需要使用& 交叉类型来扩展类型。两种使用方式看开发者的喜好自由选择。

但是 interface 可以自动合并同名类型,而 type 不可以

null 和 undefined 类型

typescript 复制代码
const testUndefined: undefined = undefined; // 定义undefined
const testNull: null = null; // 定义null

null 和 undefined 是所有类型的子类型,也就是说我们可以将 null 或者 undefined 类型的变量赋值给 string 或 number 等类型的变量

typescript 复制代码
let testUndefined: undefined = undefined;
let str = 'hello';

str = testUndefined;

let testNull: null = null;
let num: number = 123;

num = testNull;

// 同时我们也可以将null和undefined互相赋值
testNull = num;

但是如果你配置了 tsconfig.json,并开启了strictNullChecks

json 复制代码
{
  "compilerOptions": {
    "strictNullChecks": true
  }
}

这样 TS 就会对 null 和 undefined 进行严格校验

空值类型

在 TypeScript 中,void 用来表示没有任何返回值的函数

typescript 复制代码
function noop(): void {
  return;
}

在 JavaScript 中没有空值(void)的概念,对于没有任何返回值的函数,JavaScript 将隐式返回值undefined,但是 voidundefined 在 TypeScript 中并不是一回事。

typescript 复制代码
// void可以接收undefined值
let voidVar: void = undefined;

// 函数返回类型不同
function returnsVoid(): void {
  return;
}
function returnsUndefined(): undefined {
  return undefined;
}

// 在严格模式下,void类型变量不能赋给其他类型
// 但undefined类型变量可以赋给有undefined联合的类型
type MaybeString = string | undefined;
let str: MaybeString = undefined;

类型断言

typescript 复制代码
const dom: HTMLElement = document.getElementById('#root');

上面的代码在编辑器中不会报错,但是我们知道这段代码并不安全,因为我们的页面结构中可能不存在 root 这个节点,但是 TypeScript 并不知道,这个时候就需要我们来给他进行类型断言,告诉编辑器这个节点并不存在。

类型断言使用 as 这个关键字

typescript 复制代码
const dom: HTMLElement = document.getElementById('#root') as undefined;

这个时候 TypeScript 就可以推断出这个 dom 的类型是undefined

字面量类型

什么是字面量类型,就是类型字面上代表的意思。例如下面的例子中,我们创建一个函数,我们设置了字面量类型,那么我们在传参的时候,只能是这四个值中的某一个,如果我们传入别的值,那么编辑器就会报错

我们在看下面一个例子

这个时候我们就发现了,当我们使用字面量类型的时候, 虽然例子中的类型值是 string,但是我们使用 string 作为类型的话,TypeScript 就会告诉我们 string 无法传递给字面量类型。这个时候我们有两种方法来处理这个问题

  1. 在任意位置添加类型断言来处理
typescript 复制代码
// 第一种
const params = {
  url: 'http://www.baidu.com',
  method: 'GET' as 'GET',
};

// 第二种
request(params.url, params.method as 'GET');
  1. 可以使用as const将整个对象转换为类型文字
typescript 复制代码
const params = {
  url: 'http://www.baidu.com',
  method: 'GET',
} as const;

request(params.url, params.method);

as const的作用类似于 const,但是对于类型系统而言,它确保所有属性都被分配字面量类型,而不是更通用的版本,如stringnumber

类型注解和类型推断

类型注解就是之前我们文章中一直使用的方式,通过: 类型告诉 TypeScript,变量或者对象的属性类型

typescript 复制代码
// 类型注解,人工告诉TS,变量或者对象的明确属性类型
const userName: string = '张三';

但是这种方式对于开发者来说,每次都要手动添加类型,也是一种负担。所以 TypeScript 允许我们不写类型,它可以自动帮我们推导类型

typescript 复制代码
const userName = '张三';

userName.toLowerCase();

如果类型推导能够自动推断出类型,就没必要去手写类型注解。

类型收窄

typeof

在上一章中的联合类型,我们已经使用过了typeof进行过类型收窄了

这样我们获取的参数类型就是收窄过后的类型了,但是typeof并不能判断所有的类型,它只支持stringnumberbooleansymbolbigintundefinedfunctionobject

真值收窄

当我们使用可选属性的时候,参数可能不存在,这个时候我们可以使用真值收窄来进行处理

typescript 复制代码
function getContent(content?: string) {
  if (content) {
    return content.toUpperCase();
  }
}

相等收窄

当遇到两个参数有相同的类型时,我们需要使用其中一个参数上的方法,我们就可以使用相等收窄,这样 TypeScript 就会认为 x 和 y 一定是 string 类型。

typescript 复制代码
function getContent(x: string | number, y: string | boolean) {
  if (x === y) {
    return x.toUpperCase();
  }
}

in

typescript 复制代码
type Fish = {
  swim: () => void;
};

type Bird = {
  fly: () => void;
};

function test(animal: Fish | Bird) {
  // 使用 in 语法进行类型收窄
  if ('swim' in animal) {
    animal.swim();
  } else {
    animal.fly();
  }
}

类型陈述

除了通过in进行类型收窄,我们也可以使用is来判断类型

is 类型谓词的语法为 parameterName is Type,它告诉 TypeScript 编译器:

  • 如果函数返回 true,参数的类型就是指定的类型
  • 这样在条件判断中可以实现类型缩窄(type narrowing)
typescript 复制代码
type Fish = {
  swim: () => void;
};

type Bird = {
  fly: () => void;
};

// 使用 is 类型陈述
function isFish(animal: Fish | Bird): animal is Fish {
  if ((animal as Fish).swim !== undefined) {
    return true;
  }
  return false;
}

function test(animal: Fish | Bird) {
  if (isFish(animal)) {
    animal.swim();
  } else {
    animal.fly();
  }
}

总结

在本文中,我们深入学习了 TypeScript 的基础类型,包括接口的使用及其与类型别名的区别、nullundefined 的特性、voidundefined 的不同、类型断言的用法、字面量类型的应用,以及类型注解、类型推断和类型收窄的多个方法。

通过掌握这些内容,开发者可以更高效地使用 TypeScript 的类型系统,编写出类型安全、可维护的代码。

如文章有错误或者不严谨的地方,期待给于指正,万分感谢。

如果你喜欢这篇文章或者有所启发,欢迎 👉 三棵杨树,给作者一些鼓励吧!

本文源文件都放在了 Github 上,如果您觉得我写得还不错,希望您能给**❤️ 这篇文章点赞 Github加星 ❤**️ 哦~

相关推荐
芭拉拉小魔仙1 天前
【Vue3/Typescript】合并多个pdf并预览打印,兼容低版本浏览器
javascript·typescript·pdf
徐_三岁2 天前
Vue3 + TypeScript 实现 PC 端鼠标横向拖动滚动
vue.js·typescript
人工智能的苟富贵3 天前
使用 TypeScript 开发并发布一个 npm 包(完整指南)
javascript·typescript·npm
猫头虎3 天前
如何解决IDE项目启动报错 error:0308010C:digital envelope routines::unsupported 问题
javascript·ide·vue.js·typescript·node.js·编辑器·vim
啊花是条龙3 天前
使用 Axios 和 AbortController 实现请求控制和取消
react.js·typescript
parade岁月4 天前
TypeScript 全局类型声明文件规范性分析与归纳
前端·vue.js·typescript
胖方Hale4 天前
11. Typescript 泛型
前端·typescript
浪裡遊4 天前
TypeScript之基础知识
前端·javascript·typescript
孟陬4 天前
TypeScript 系列:satisfies 的实用之处
typescript
Zhillery4 天前
Tauri快速入门1 - 搭设开发环境
typescript·前端框架·react·tauri