TypeScript 学习笔记
1.准备工作
要想编译ts文件必须安装TS的工具包,这个安装包可以将TS代码转为JS代码,然后才能运行
安装命令
npm i -g typescript //安装命令
typescript 包:用来编译TS代码的包,提供了 TSC 命令,实现了 TS -> JS 的转化
2.编译并且运行TS代码
- 创建hello.ts 文件
- 将TS编译为JS:在终端输入命令,
tsc hello.ts - 执行JS命令:在终端中输入命令,
node hello.js
3.简化运行TS步骤
当前我如果修改代码后,都需要重复执行两个命令,才能执行TS代码,过于繁琐
- 简化方法:使用ts-node包,直接在Node.js中执行TS代码
- 安装命令:
npm i -g ts-node - 使用方式:
ts-node hello.ts - 原理:ts-node命令内部偷偷的将TS -> JS,再运行JS代码
4.TypeScript常用类型
4.1 类型注解
作用就是为变量添加类型约束,约定了什么类型,就只能给变量赋值该类型的值,否则就会报错
let age:number=18
age=12 //正确
age='12' //类型错误
4.2 常用基础类型概述
可以将TS中的常用基础类型细分为两类:1.JS已有类型 2.TS新增类型
- JS已有类型
- 原始类型:number/string/boolean/null/undefine/symbol
- 对象类型:object(包括,数组、对象、函数等对象)
- TS新增类型
- 联合类型、自定义类型(类型别名)、接口、元组、字面量类型、枚举、void、any等
1. 原始类型
特点:简单,这些类型,完全按照js中类型的名称来书写
2. 数组类型
两种写法:(推荐使用第一种)
let numbers: number[] = [1, 2, 3, 4];
let strings: Array<string> =['a','b','c']
需求:数组中既有number类型,又有string类型,这个数组的类型怎么写?
3. 联合类型
使用一根 | 竖线来表示联合
let arr :(number|string)[] = [1,2,3,'4']
4. 类型别名(自定义类型)
当同一类型(复杂)被多次使用时,可以通过类型别名,简化该类型的使用(相当于在申明变量)
type CustomArray = (number|string)[] //类型别名
let arr2:CustomArray = [1,2,3,'sd','we']
let arr3:CustomArray = ['sd','we',1,2]
5. 函数类型
函数的类型实际上指的是:函数参数和返回值的类型。 为函数指定类型的两种方式:1.单独指定参数、返回值的类型 2.同时指定参数、返回值的类型。
const add = function(name: string, age: number): void {
console.log(`你好,我的名字叫${name},我的年龄是${age}岁`);
//这里使用模板字面量,好处是:模板字面量通常更易于阅读和维护,
//尤其是在处理包含多个变量或复杂表达式的字符串时,
//对于非常长的字符串或大量的拼接操作,模板字面量可能会稍微快一些,
//因为它们在内部使用更高效的方法来处理字符串和变量的组合
}
add('wjw',23)
type addType = (name: string, age: number,address?:string)=> void
const addmethod:addType = function(name,age,address?){
if(address!==null||address!==undefined){
console.log(`你好,我的名字叫${name},我的年龄是${age}岁,我的家在${address}`);
}
else
console.log(`你好,我的名字叫${name},我的年龄是${age}岁`);
}
addmethod('yke',20,'莲湖')
6. 对象类型
JS中的对象由属性和方法构成,而TS中的对象的类型就是在描述对象的结构
//定义一个对象类型
type objType = {
name: string;
age: number;
getName(): string;
getAge?(): number; //对象的可选函数
};
//创建一个objType类型的对象
let person: objType = {
name: "wjw",
age: 18,
getName: function () {
return this.name; //这里使用this的话,方法就不能写成箭头函数
},
getAge: function () {
console.log(`你好${JSON.stringify(this)},我刚满${person.age}`);
return person.age;
},
};
person.getAge!(); //调用可选函数必须加上! 断言
可选属性和方法
- 比如在使用axios({...})时,如果发送的是GET请求,method就可以省略,使用“ ? ”来表示
function myAxios(config:{url: string;method?:string}){ //使用?来表示method是可选属性
console.log(config);
}
7. 接口
当一个对象类型被多次使用时,一般会使用接口来描述对象的类型,达到复用的目的
interface IPerson{
name: string
age: number
sayHi(name?:string): void
}
let person2: IPerson={
name: "wjw",
age: 18,
sayHi: function (name?: string | undefined): void {
let defaultName='默认名称'
defaultName=name?name:defaultName
console.log(`${defaultName},你好,${this.name}`)
}
}
person2.sayHi('wjw2')
7.1 interface(接口)和type(类型别名)的区别
- 相同点:都可以给对象指定类型
- 不同点:
- 接口:只能为对象指定类型
- 类型别名:不仅可以为对象指定类型,实际可以为任意类型指定别名
7.2 接口继承
如果两个接口之间有相同的属性或方法,可以将公共的属性或方法抽离出来,通过继承实现复用
- 使用extends关键字实现接口的继承
- 继承后,继承的接口就有了被继承接口的所有属性和方法
interface IPoint1{
x: number
y: number
getX(): number
getY(): number
}
interface IPoint2{
x: number
y: number
getX(): number
z: number
}
//上述两个接口很多公共的属性和方法,重复写两次很繁琐,所以我们使用接口之间继承的方式
使用继承后:
interface IPoint1{
x: number
y: number
getX(): number
getY(): number
}
interface IPoint2 extends IPoint1{
z:number
}
8. 元组
使用场景:在地图中,经常使用经纬度坐标来标记位置信息
可以使用数组来记录坐标,那么该数组中只有两个元素,并且这两个元素都是数组类型
let position:number[] = [32.123,54.123]
使用number[]的缺点:不严谨,因为该类型的数组中可以出现任意多个数字 更好的方式:使用元组
元组类型是另外一种类型的数组,它确切的知道包含了多少个元素,一级特定索引对应的类型
let position:number[number,number] = [32.123,54.123]
9. 类型推论
在TS中,某些没有明确指出类型的地方,TS的类型推论机制会帮助提供类型。换句话说:由于类型推论的存在,这些地方,类型推论可以不写。 发生类型推论的2种常见场景:1. 声明变量并且初始化 2. 决定函数返回值时
let num = 12 //声明变量并且初始化,类型推论生效,可以省略类型
num='123' //报错
let result //注意:如果只是声明变量,而没有初始化值,建议手动添加类型注解,不建议省略
result = 1
result = '1' //不报错
function add(num1:number,num2:number){//可以省略返回值的类型注解
return num1+num2
}
10. 类型断言
有时候我们会比TS更能明确一个值的类型,此时,可以使用类型断言来指定具体的类型
类比java来说,我们拿到父类对象,但其实我们像调用子类的方法或者属性,那么我们就需要向下转型,因为父类里可能没有子类的方法或属性。同理,类型断言就是强制告诉TS我要的类型是什么
类型断言使用 as 关键字
const sonObject = father as son //第一种写法
const sonObject = <son>father //第二种写法(不常用)
11. 字面量类型
先看以下两个变量的类型分别是什么?
let str1 = 'Hello'
const str2 = 'Hello'
通过TS类型推论机制,可以得到答案:
- 变量str1的类型为:string
- 变量str2的类型为:'Hello'
解释:str1是一个变量(let),他的值可以是任意字符串,所以类型是string。str2是一个常量(const),他的值不能变化只能是'Hello',所以,他的类型为'Hello'。
此处的'Hello',就是一个字面量类型,也就是说某个特定的字符串也可以作为TS中的类型
const str2:'Hello' = 'Hello'
let age:18 = 18
字面量类型通常配合联合类型一起使用,用来表示一组明确的可选值列表 比如在贪吃蛇游戏中,游戏的方向的可选值只能是:上下左右 中的任意一个
function changeDirection(direct:'up'|'down'|'left'|'right'){
console.log(direct)
}
解释:参数direct的值只能是up/down/left/right 中的任意一个 优势:相比于string类型,使用字面量类型更加严谨准确
12. 枚举
枚举的功能类似于字面量类型+联合类型组合的功能,也可以表示一组明确的可选值
枚举:定义一组命名常量。他描述一个值,该值可以是这些命名变量中的一个
enum Direction {Up,Down,Left,Right}
function changeDirection(direct:Direction){
console.log(direct)
console.log(typeof direct)
}
changeDirection(Direction.Up)
上面我们把枚举成员作为了函数的实参,它的值是什么? 解释:通过鼠标移入Direction.Up,可以看到枚举成员Up的值为0
12.1 数字枚举
注意:枚举成员是有值的,默认为:从0开始自增的数值 我们把枚举成员的值为数字的枚举,称为:数字枚举。 当然,也可以给枚举中的成员初始化值
//Down=11,Left=12,Right=13
enum Direction {Up=10,Down,Left,Right}
enum Direction2 {Up=2,Down=5,Left=8,Right=10000}
12.2 字符串枚举
枚举成员的值是字符串 注意:字符串枚举没有自增长行为,因此,字符串枚举的每个成员必须有初始值
enum Direction{
Up = 'UP',
Down = 'DOWN',
Left = 'LEFT',
Right = 'RIGHT'
}
13. any类型
原则:不推荐使用any! 这会让TypeScript 变为 AnyScript (失去TS类型保护的优势)
14. typeof
TS中的typeof操作符可以在类型上下文中引用变量或属性的类型(类型查询) 使用场景:根据已有变量的值,获取该值的类型,来简化类型书写
let p = {x:1,y:2}
//我在定义函数时,函数参数类型可以由p.x这个属性来判断,如果该属性值是123,他的类型就是number,如果是'abc',他的类型就是string。这个类型就可以通过 typeof 来获取到
function change(point:typeof p.x){
}