一、TypeScript概述
TypeScript 是 JavaScript 的一个超集,支持 ECMAScript 6 标准(ES6 教程)。
TypeScript 由微软开发的自由和开源的编程语言。
TypeScript 设计目标是开发大型应用,它可以编译成纯 JavaScript,编译出来的 JavaScript 可以运行在任何浏览器上。
编程语言,分为了“强类型语言”和“弱类型语言”。
强类型语言,对于数据类型要求非常严格,不允许不同类型的数据之间做隐式转换。
弱类型语言,对于数据类型要求不严格,不同的数据类型之间可以进行相互的转换。
静态类型检查
静态类型检查,指的是在代码编写的过程中,就开始对代码语法进行检查。也就是说,在代码运行之前,就可以检查出代码语法报错的地方。
因此我们前端开发,会慢慢选择用 TS 来代替 JS,就是因为 JS 是弱类型语言,而 TS 属于强类型语言。
1、安装typeScript
安装nodejs
官网:https://nodejs.p2hp.com/download/
nodejs的版本不要低于18
安装完成后在cmd窗口输入 node -v命令即可查看安装的nodejs信息
设置npm源
由于npm服务器在国外下载比较慢,一般会改为国内的镜像服务器。在cmd窗口输入如下命令
npm config set registry https://mirrors.huaweicloud.com/repository/npm/ #华为 或 npm config set registry https://registry.npmmirror.com #阿里
安装 typescript
npm i -g typescript
安装完成后我们可以使用 tsc 命令来执行 TypeScript 的相关代码,以下是查看版本号:
tsc -v Version 5.5.3
二、TypeScript 数据类型与变量
typeScript 程序由以下几个部分组成:
- 模块
- 函数
- 变量
- 语句和表达式
- 注释
TypeScript 区分大写和小写字符。
1、TypeScript 注释
- 单行注释 ( // ) − 在 // 后面的文字都是注释内容。
- 多行注释 (/* */) − 这种注释可以跨越多行。
// 这是一个单行注释 /* 这是一个多行注释 这是一个多行注释 这是一个多行注释 */
2、TypeScript数据类型
基本类型:数字 number、字符串 string、布尔值 boolean、空 null、未定义 undefined、唯一值 symbol、无穷大 bigInt
引用类型:**数组 array、对象 object、**元组 tuple、枚举 enum、函数 function
特殊类型:任意类型 any、任意类型 unknown、void、never
高级类型:联合类型、交叉类型
3、TypeScript 变量
TypeScript 变量的命名规则:
- 变量名称可以包含数字和字母。
- 除了下划线 _ 和美元 $ 符号外,不能包含其他特殊字符,包括空格。
- 变量名不能以数字开头。
语法: var [变量名] : [类型] = 值; 示例: var uname:string = "Runoob";
声明变量并初始值,但不设置类型,该变量可以是任意类型:
语法: var [变量名] = 值; 示例: var uname = "Runoob";
a、基本类型
var a: number = 1; let b: string = 'hello'; const c: boolean = true; let d: undefined = undefined; let e: null = null; b = 100; // 报错
b、数组
默认情况下,在 TS 中,要求数组内部只能保存同一个类型的数据
let a: number[] = [1, 2, 3];let b: string[] = ['a', 'b'];
c、对象
可以通过 object 来设置对象的类型,但是设置成 object 类型后,不能单独访问对象内部的任意属性。
let a: object = {id: 1,name:'张三'}; console.log(a.id); // 报错,不能确定 a 身上存在 id 属性
我们更常用的对象约束类型的方式,是针对对象中每一个属性以及每一个属性值的类型都一一进行约束:
let a: { id: number, name: string } = {id: 1,name: '张三'} console.log(a.id);
如果有某一些属性是可有可无的,可以在约束类型时,在属性名后面添加 ?
:
let a: { id: number, name: string, age?: number } = {id: 1,name:'张三',}
d、元组
从代码语法上来看,元组实际上就是数组,但是它和数组的区别在于,元组中可以报错不同类型的数据。
let a: [number, string, number] = [1, '2', 3];
元组语法要求,数组中的每一条数据,都必须对应着一个类型。
e、枚举
当数据中有一些不确定含义的数字时,可以定义一个枚举类型,来描述每一个数字所对应的含义:
enum GenderEnum {woman = 0,man = 1,unknown = 2}
定义好的枚举类型,既可以当作类型来用,也可以当作值来用:
let student: { name: string, gender: GenderEnum } = {name: '张三',gender: GenderEnum.man,}
f、any 和 unknown
any 和 unknown 都可以用来表示任意类型的数据。
let a: any = 1; a = 'hello'; let b: unknown = 1; b = 'hello'; let c: boolean = true; c = a; // 不报错// c = b; // 报错
any 和 unknown 的区别在于:
- any 类型的数据可以再次赋值给其他任意类型;unknown 类型的数据只能赋值给其他的 unknown 或 any;
- 数据一旦设置为 any 类型后,会关闭 TS 的类型检查;数据设置为 unknown 后,还是会进行类型检查。
g、void
void,当一个函数内部没有设置返回值时,返回值的类型就是 void:
const foo = (): void => {}
h、never
never 用来表示永远都不会有值的数据的类型:
const foo = (): never => {while(true) { }}
TS 中的函数可以像 JS 中一样的使用,但是 TS 中要求对函数进行类型约束:
- 约束参数的类型;
- 约束返回值的类型;
- 约束函数自身的类型;
三、TypeScript函数
1、基本语法
语法结构:
function 函数名(形参: 参数类型, 形参: 参数类型): 返回值类型 { return 返回值; } 函数名(数据, 数据);
示例代码:
方式一: function foo(x: number, y: number): number { return x + y; }; foo(1, 2);//调用函数foo 方式二:【推荐】 const bar = (x: number, y: number): number => { return x + y; } bar(10, 20);//调用函数bar
2、函数参数
a、参数默认值
function foo(x: number, y: number = 0): number { return x + y; }; foo(1, 2);
注意:带有默认值的参数通常放在所有形参的最后。
b、不定参数
const bar = (y: number, ...x: number[]) => { } bar(10, 20, 30, 40);
注意:不定参数通常放在所有形参的最后。
c、可选参数
function foo(x: number, y?: number) { }; foo(1);
注意:可选参数通常放在所有形参的最后。
3、函数自身的类型约束
TS 是一个可选的静态的类型系统,可以用来约束变量、函数的参数和返回值。仅需要在变量、函数的参数和返回值位置加上" : 类型 "
变量
let name:string;
函数
const bar=(x: number,y: number)=>{ return x + y; } console.log(bar(1,2));
四、TypeScript高级类型
1、类型别名
类型别名的作用,就是对已经存在的类型进行重命名。
type bool = boolean; //为boolean类型取别名bool let a: bool = true; //使用别名bool做为数据类型
通常,我们可以对一个对象的类型,进行别名配置
type StudentItem = { id: number, name: string, age?: number }; let a: StudentItem = {id: 1,name: '张三',}
2、联合类型
联合类型就是通过 |
来定义多个类型,数据只要匹配多个类型中的任意一个即可
let a: number | string | boolean = 'hello';
当数组中需要包含多个类型的数据时,就可以通过联合类型来设置数组内部数据的类型。
let a: (number | string)[] = [1, 2, 3, '4', '5']
联合类型和类型别名可以一起使用
type NumStr = number | string; let a: NumStr[] = [1, 2, 3, '4', '5']; let b: NumStr = 'hello';
3、交叉类型
交叉类型就是通过 &
来将多个类型合并成一个类型。
type Person = {id: number,name: string,age: number}; type Address = {province: string,city: string}; let student: Person & Address = {id: 1,name: '张三',age: 20,province:'四川',city: '成都'};
注意:交叉类型通常只能用来对象类型身上,将多个对象合并成一个对象。
交叉类型也可以和类型别名一起使用
type Person = {id: number,name: string,age: number}; type Address = {province: string,city: string,}; type StudentItem = Person & Address; let student: StudentItem = {id: 1,name:'张三',age: 20,province:'四川',city:'成都'};
五、类型断言
类型断言是一种方式,可以手动指定变量的类型,非空断言是一种类型断言的特殊形式,
类型断言,指的是在某些特殊情况下,我们比 TS 更加确定数据的类型。因此,这种时候我们可以通过断言的方式来断定数据的类型。
1、基本语法
断言提供了两种语法:
<>
as
:推荐用 as
语法结构如下:
<类型>数据 as 类型
示例代码:
let arr: number[] = [1, 2, 3, 4]; //定义数组 //查找数组中>=2的元素,返回的值为number const result = arr.find((item) => { return item >= 2; }) 改为如下则会报错,因为ts不知道结果的类型 const result: number = arr.find((item) => { return item >= 2; }) 上面的情况我们很确定结果的类型number但是ts无法确定,可以使用断言确定其返回值果就是number类型 const result: number=<number>arr.find((item)=>{ return item>=2 }) 也可以写成如下形式 const result: number = arr.find((item) => { return item >= 2; }) as number;
2、非空断言
TS 中可以通过 !
来对数据进行非空断言,断定数据不会是 undefined 或 null。
语法结构:
数据!
示例代码:
const result: number = arr.find((item) => { return item >= 2; })!
六、接口 interface
1、接口和对象
接口,可以用来定义对象或函数的类型。
a、基本语法
语法
interface 接口名 { 属性名: 数据类型; 属性名: 数据类型; }
示例 :
//定义接口 interface StudentItem { id: number; name: string; age: number; } //将接口做为数据类型 const student: StudentItem = { id: 1, name: '张三', age: 20, }
b、可选属性
在接口中使用?修饰的属性在使用时可以不指定值
//定义接口 interface StudentItem { id: number; name: string; age?: number; } //创建对象 const student: StudentItem = { id: 1, name: '张三', }
c、只读属性
在接口中使用readonly 修饰的属性不能重新赋值
//定义接口 interface StudentItem { readonly id: number; //id属性被设置为只读 name: string; age: number; } //创建对象 const student: StudentItem = { id: 1, name: '张三', age: 20, } //改变对象中属性的值 student.id = 2; // 报错
2、接口和函数
语法: interface 接口名 { 属性名: 数据类型; 属性名: 数据类型; } 示例: interface BarFn { (x: number, y: number): number } const bar: BarFn = (x, y) => { return x + y; } bar(1, 2);
3、接口和接口
在一个接口中,可以去使用另一个接口,同理,也可以使用当前接口自身。
interface MenuItem { id: number, title: string, children?: MenuItem[] } const menusData: MenuItem[] = [ { id: 1, title: '首页' }, { id: 2, title: '用户管理', children: [ { id: 3, title: '用户列表' }, { id: 4, title: '用户分组' } ] } ]