Typescript学习笔记

思维导图

1. TypeScript 介绍

1.1 TypeScript 是什么

  • TypeScript(简称:TS)是 JavaScript 的超集(JS 有的 TS 都有)
  • TypeScript = Type + JavaScript(在 JS 基础之上,为 JS 添加了类型支持)。
  • TypeScript 是微软开发的开源编程语言,可以在任何运行 JavaScript 的地方运行。
  • 官网:https://www.typescriptlang.org/
  • 中文官网:https://www.tslang.cn/
    在这里插入图片描述

1.2 TS为何添加类型支持

背景:JS 的类型系统存在“先天缺陷”,JS 代码中绝大部分错误都是类型错误(Uncaught TypeError)。
问题:增加了找 Bug、改 Bug 的时间,严重影响开发效率。


从编程语言的动静来区分,TypeScript 属于静态类型的强类型编程语言(先编译再执行),JS 属于动态类型的弱类型编程语言。

  • 静态类型:编译期做类型检查;
  • 动态类型:执行期做类型检查。

  • 对于 JS 来说:需要等到代码真正去执行的时候才能发现错误(晚)。
  • 对于 TS 来说:在代码编译的时候(代码执行前)就可以发现错误(早)。
  • 结论:配合 VSCode 等开发工具,TS 可以提前到在编写代码的同时就发现代码中的错误,减少找 Bug、改 Bug 时间

1.3 TS 相比 JS 的优势

  1. 更早(写代码的同时)发现错误,减少找 Bug、改 Bug 时间,提升开发效率。
  2. 程序中任何位置的代码都有代码提示,随时随地的安全感,增强了开发体验。
  3. 强大的类型系统提升了代码的可维护性,使得重构代码更加容易。
  4. 支持最新的 ECMAScript 语法,优先体验最新的语法,走在前端技术的最前沿。
  5. TS 类型推断机制,不需要在代码中的每个地方都显示标注类型,在享受优势的同时,尽量降低了成本。

2. TypeScript 初体验

2.1 安装编译 TS 的工具包

Node.js/浏览器,只认识 JS 代码,不认识 TS 代码。需要先将 TS 代码转化为 JS 代码,然后才能运行。 所以需要安装编译 TS 的工具包

安装命令:

npm i -g typescript

这个typescript 包是用来编译 TS 代码的包,提供了 tsc 命令,实现了 TS -> JS 的转化。
在这里插入图片描述
验证是否安装成功:终端 tsc –v(查看 typescript 的版本)。有版本显示表示安装成功

2.2 编译并运行 TS 代码

步骤

  1. 创建 hello.ts 文件(注意:TS 文件的后缀名为 .ts)。
  2. 将 TS 编译为 JS:在终端中输入命令,tsc hello.ts(此时,在同级目录中会出现一个同名的 JS 文件)。
  3. 执行 JS 代码:在终端中输入命令,node hello.js

在这里插入图片描述

说明:所有合法的 JS 代码都是 TS 代码,有 JS 基础只需要学习 TS 的类型即可。
注意:由 TS 编译生成的 JS 文件,代码中就没有类型信息了。

2.3 简化运行 TS 的步骤

  • 问题描述:每次修改代码后,都要重复执行上述两个命令,才能运行 TS 代码,- 太繁琐。
  • 简化方式:使用 ts-node 包,“直接”在 Node.js 中执行 TS 代码。
  • 安装命令:npm i -g ts-node(ts-node 包提供了 ts-node 命令)。
  • 使用方式:ts-node hello.ts
  • 解释:ts-node 命令在内部偷偷的将 TS -> JS,然后,再运行 JS 代码。

3. TypeScript 常用类型

  • TS 提供了 JS 的所有功能,并且额外的增加了:类型系统
  • JS 有类型(比如,number/string 等),但是 JS 不会检查变量的类型是否发生变化。而 TS 会检查。
  • TypeScript 类型系统的主要优势:可以显示标记出代码中的意外行为,从而降低了发生错误的可能性。

3.1 类型注解

let age: number = 18;
  • 说明:代码中的 : number 就是类型注解,为变量添加number(数值)类型约束。
  • 解释:约定了什么类型,就只能给变量赋值该类型的值,否则,就会报错。

3.2 常用基础类型概述

可以将 TS 中的常用基础类型细分为两类:JS 已有类型TS 新增类型

  • JS 已有类型
    • 原始类型(简单类型/值类型):number/string/boolean/null/undefined/symbol。
    • 对象类型(复杂类型/引用类型):object(包括,数组、对象、函数等对象)。
  • TS 新增类型
    • 联合类型、自定义类型(类型别名)、接口、元组、字面量类型、枚举、void、any 等。

3.3 原始类型

  • 原始类型:number/string/boolean/null/undefined/symbol。
  • 特点:简单。这些类型,完全按照 JS 中类型的名称来书写。
let age: number = 16; 
let myName: string = '凉宫';
let flag: boolean = false;
let a: null = null;
let b: undefined = undefined;
let s: symbol = Symbol();

3.4 数组类型

对象类型(包括,数组、对象、函数等对象),在 TS 中更加细化,每个具体的对象都有自己的类型语法

数组类型的两种写法:(推荐使用 number[] 写法)

let arr1: number[] = [1, 3, 4];
let arr2: Array<number> = [1, 2, 4];
let arr3: boolean[] = [true, false, true];
let arr4: string[] = ["a", "1", "凉宫"];
// ...其他类型同理
// let arr5: string[] = [true, 2, 'abc'] 错误,数组中的元素只能是string类型

3.5 联合类型

  • 联合类型表示取值可以为多种类型中的一种,使用单个 | 竖线分隔每个类型
  • 注意:这是 TS 中联合类型的语法,只有一根竖线,不要与 JS 中的或(||)混淆。
let money: number | string = 3;// 变量money可以是数值类型或字符串类型
// 添加括号 表示:arr1前提是数组,然后元素的值可以是number或string类型
let arr1: (number | string)[] = [1, 5, "1", "abc"];
// 不添加括号 表示: 可以arr2可以是number类型 或 元素为string类型的数组
// let arr2: number | string[] = [1, 5, "1", "abc"]; // 会错误
// let arr3: number | string[] = 12; // 正常
// let arr4: number | string[] = ["1", "ac", "凉宫"]; // 正常

3.6 类型别名

  • 类型别名(自定义类型):为任意类型起别名。
  • 使用场景:当同一类型(较复杂)被多次使用时,可以通过类型别名,简化该类型的使用。
type CustomArray = (number | string)[];
let arr1: CustomArray = [1, 2, "3", "abc"]; // ok
// let arr2: CustomArray = [1, 2, "3", true] // 报错

细节:

  1. 使用 type 关键字来创建类型别名。
  2. 类型别名(比如,此处的 CustomArray),可以是任意合法的变量名称。
  3. 创建类型别名后,直接使用该类型别名作为变量的类型注解即可。

3.7 函数类型

3.7.1 两种基本用法

  • 函数的类型实际上指的是:函数参数和返回值的类型。
  • 为函数指定类型的两种方式:
    • 1 单独指定参数、返回值的类型
    • 2 同时指定参数、返回值的类型。

1、 单独指定参数、返回值的类型

  • 参数类型在参数后面加上 类型注解,返回值的类型是在参数小括号后面加上类型注解
  • 注意1:若加了返回值的类型,则必须要有返回值,且值符合类型要求
  • 注意2:若加了参数的类型,则调用时必须依照形参的格式传入实参(个数,类型,顺序)
function add(num1: number, num2: number): number {
   
  return num1 + num2;
}
const add2 = (num1: number, num2: number): number => {
   
  return num1 + num2;
};
function add1(): number {
   
  return 10;
}
add(1, 2);

2、 单独指定参数、返回值的类型

  • 当函数作为表达式时,可以通过类似箭头函数形式的语法来为函数添加类型。
  • 注意:这种形式只适用于函数表达式,不适用函数声明式。
// const add = (num1, num2) => {
   
//   return num1 + num2; // 这种用法观感上可能不太清晰
// };
// 把第一个冒号开始到第二个等号之前作为一个整体,去掉即为普通函数
const add: (num1: number, num2: number) => number = (num1, num2) => {
   
  return num1 + num2; // 这种用法观感上可能不太清晰,那就用第一种吧
};
add(1, 2);

3.7.2 void类型-无返回值

如果函数没有返回值,那么,函数返回值类型为:void

function greet(name: string): void {
   
  console.log(name);
}
greet("凉宫");

3.7.3 可选参数

使用函数实现某个功能时,参数可以传也可以不传。这种情况下,在给函数参数指定类型时,就用到可选参数了。

比如,数组的 slice 方法,可以 slice() 也可以 slice(1) 还可以 slice(1, 3)

function Myslice(start?: number, end?: number): void {
   
  console.log("起始索引" + start + "结束索引" + end);
}
Myslice();
Myslice(2);
Myslice(2, 5);

可选参数:在可传可不传的参数名称后面添加 ?(问号)。
注意:可选参数只能出现在参数列表的最后,可选参数后面不能出现必选参数。

3.8 对象类型

3.8.1 基本用法

JS 中的对象是由属性和方法构成的,而 TS 中对象的类型就是在描述对象的结构(有什么类型的属性和方法)。写法如下

// 先申明JS中的写法,在变量后面加 :{ }  在中括号里指定类型
let person: {
    name: string; age: number; say(): void } = {
   
  name: "zs",
  age: 20,
  say() {
   },
};
let person2: {
   
  name: string;
  age: number;
  greet(name: string): void;
} = {
   
  name: "zs",
  age: 18,
  greet(name) {
   
    console.log("hello" + name);
  },
};
person2.greet("凉宫");
  1. 直接使用 {} 中来描述对象结构。属性采用属性名: 类型的形式;方法采用方法名(): 返回值类型的形式。
  2. 如果方法有参数,就在方法名后面的小括号中指定参数类型(比如:greet(name: string): void)。
  3. 在一行代码中指定对象的多个属性类型时,使用 ;(分号)来分隔。
  • 如果一行代码只指定一个属性类型(通过换行来分隔多个属性类型),可以去掉 ;(分号)。
  • 方法的类型也可以使用箭头函数形式(比如: sayHi: () => void )。

3.8.2 可选属性

对象的属性或方法,也可以是可选的,此时就用到可选属性了。
比如,在使用 axios({ … }) 时,如果发送 GET 请求,method 属性就可以省略。

function myAxios(config: {
    url: string; method?: string }) {
   }
myAxios({
   
  url: "www.baidu.com",
  // 这里不传method方法可以是可以的
});

可选属性的语法与函数可选参数的语法一致,都使用 ?(问号)来表示。

3.9 接口

3.9.1 基本使用

当一个对象类型被多次使用时,一般会使用接口(interface)来描述对象的类型,达到复用的目的。

// 声明接口
interface IPerson {
   
  name: string;
  age: number;
  sayHi(): void;
}
// 实现接口
let person: IPerson = {
   
  name: "zs",
  age: 20,
  sayHi() {
   },
};

细节:

  1. 使用 interface 关键字来声明接口。
  2. 接口名称(比如,此处的 IPerson),可以是任意合法的变量名称。
  3. 声明接口后,直接使用接口名称作为变量的类型。
  4. 若要实现接口,必须实现接口中的所有的属性和方法,否则报错

3.9.1 接口 vs 类型别名

interface(接口)和 type(类型别名)的对比:

  • 相同点:都可以给对象指定类型。
  • 不同点:
    ① 接口,只能为对象指定类型。
    ② 类型别名,不仅可以为对象指定类型,实际上可以为任意类型指定别名。
// 声明接口
interface IPerson {
   
  name: string;
  age: number;
  sayHi(): void;
}
// 声明类型别名;两者比较像,注意区分
type IPerson2 = {
   
  name: string;
  age: number;
  sayHi(): void;
};
type numStr = number | string;
//用法上没有区别
let person2: IPerson2 = {
    name: "zs", age: 20, sayHi() {
   } };
let person: IPerson = {
    name: "zs", age: 20, sayHi() {
   } };

3.9.3 接口继承

如果两个接口之间有相同的属性或方法,可以将公共的属性或方法抽离出来,通过继承来实现复用


                
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值