以此篇,来开启自己的TypeScript学习之旅
> --Tricia
认识TypeScript
TypeScript 简称:TS,是 JavaScript 的超集 ,简单来说就是:JS 有的 TS 都有
- TypeScript =
Type+ JavaScript(在 JS 基础之上,为 JS 添加了类型支持) - TypeScript 是微软开发的开源编程语言,可以在任何运行 JavaScript 的地方运行
为什么要有typescript
js缺点?
-
JS 的类型系统存在“先天缺陷”弱类型,JS 代码中绝大部分错误都是类型错误(Uncaught TypeError)
- 开发的时候,定义的变量本应该就有类型
-
这些经常出现的错误,导致了在使用 JS 进行项目开发时,增加了找 Bug、改 Bug 的时间,严重影响开发效率
为什么会这样?
-
从编程语言的动静来区分,TypeScript 属于静态类型的编程语言,JavaScript 属于动态类型的编程语言
- 静态类型:编译期做类型检查
- 动态类型:执行期做类型检查
-
代码编译和代码执行的顺序:1 编译 2 执行
-
对于 JS 来说:需要等到代码真正去执行的时候才能发现错误(晚)
-
对于 TS 来说:在代码编译的时候(代码执行前)就可以发现错误(早)
安装编译 TS 的工具包
Node.js和浏览器只认识 JS 代码,不认识 TS 代码。需要先将 TS 代码转化为 JS 代码,然后才能运行
安装命令:
npm i -g typescript
# 或者
yarn global add typescript
ts简单数据类型
ts类型分为两大类
- js已有类型
- ts新增类型
let num :number = 100
let str :string = 'hello'
let boo :boolean = true
boo = !0
let param :null = null
let param2 :undefined = undefined
// any类型可以赋值给任意类型
let any :any = 'hello'
any = 100
// void类型只能赋值undefined和null
let voids :void = undefined
// let voids1 :void = null
// never类型表示永远不存在的值
// never类型只能赋值给never类型
类型别名
-
类型别名(自定义类型):为任意类型起别名 推荐大写开头type 自定义类型别名 = 类型
-
使用场景:当同一类型(复杂)被多次使用时,可以通过类型别名,简化该类型的使用
type MyType = (string | number | boolean)[]
let arr : MyType = [1,'a',true]
let arr2 : MyType = [1,'a',false, 888, 'hshs']
let arr3 : MyType = [1, 888, 'hshs', false]
type MyVarType = number | string | boolean
let param1 : MyVarType = 'hello'
let param2 : MyVarType = true
let param3 : MyVarType = 100
ts复杂数据类型
数组类型
方式一
let 变量名 :类型注解[] = [值]
// 表示数组中只能存数字
let arr :number[] = [1,2,3]
// 表示数组中只能存字符串
let arr2 :string[] = ['a','b','c']
方式二
let 变量名 :Array<类型注解> = [值]
let arr3 :Array<number> = [1,2,3]
let arr4 :Array<string> = ['a','b','c']
let arr5 :Array<boolean> = [true,false,!0]
联合类型
联合类型将多个类型组合成一个类型
{
// 联合类型
// temp变量,可以存 string number Boolean 三种类型
let temp : string | number | boolean = 100
temp = 'hello'
temp = true
// 实际应用中存定时器id 默认会给null,后面会改成number
let timeId : number | null = null
timeId = window.setInterval(() => {
console.log('hello')
}, 1000)
// 需求 数组中可以存数字,字符串,也可以存布尔值
let arr : (boolean | number | string)[] = [1,'a',true]
let arr2 : Array<boolean | number | string> = [1,'a',false]
}
函数类型
基本类型
-
函数指定类型:其实是在给函数的参数和返回值指定类型
function 函数名(参数1 : 类型, 参数2 : 类型) : 返回值类型 {函数体}
-
为函数指定类型的两种方式:
- 单独指定参数、返回值的类型
function add(n : number, m : number) : number { return n + m } add(1, 2) const sub = (n : number, m : number) : number => { return n - m } sub(20, 10) const fn = function(n : number, m : number) : number { return n * m } fn(1, 2)-
使用自定义类型 同时指定参数、返回值的类型(不常用)
type 自定义类型 = (参数1 : 类型, 参数2 : 类型) => 返回值类型
// 自定义函数类型 只适用于函数表达式和箭头函数 // type 自定义类型 = (参数1 : 类型, 参数2 : 类型) => 返回值类型 type MyFnType = (n : number, m : number) => number const sub : MyFnType = (n , m) => { return n - m } sub(20, 10) const fn : MyFnType = function(n , m) { return n * m } fn(1, 2)
void类型
如果函数没有返回值,那么,函数返回值类型为:void
// 如果函数没有返回值,那么,函数返回值类型为:void
const fn2 = () => {}
// 这种写法是明确指定函数返回值类型为 void,与上面不指定返回值类型相同
const fn3 = () : void => {
console.log('hello')
}
// 如果指定 返回值类型为 undefined,此时,函数体中必须显示的 return undefined 才可以
const fn4 = () : undefined => {
return undefined
}
可选参数
-
可选参数,可以不传参数,也可以传参数
-
可选参数:在可传可不传的参数名称后面添加
?(问号) -
注意
- 可选参数只能出现在参数列表的最后,也就是说可选参数后面不能再出现必选参数
function mySlice(start?: number, end?: number): void {
console.log('起始索引:', start, '结束索引:', end)
}
对象类型
TS 对象的类型就是在描述对象的结构 (有什么类型的属性和方法)
-
写法
-
使用
{}来描述对象结构 -
属性采用
属性名: 类型的形式 -
方法采用
方法名(): 返回值类型的形式- 方法的类型也可以使用箭头函数形式
-
// 对象类型说明
type PersonType = {
name: String,
age: Number,
gender: String,
sing : (song : string) => void
run() : void
}
const obj : PersonType = {
name : 'Tt',
age : 18,
gender : '女',
sing : (song) => {
console.log('我会' + song)
},
run() {
console.log('跑800m 3min');
},
}
obj.sing('小小小小小')
接口类型
当一个对象类型被多次使用时,一般会使用接口(interface)来描述对象的类型,达到复用的目的。
基础用法 ****
- 使用
interface关键字来声明接口 - 接口名称(比如,此处的 IPerson),可以是任意合法的变量名称,推荐以
I开头 - 声明接口后,直接使用接口名称作为变量的类型
- 因为每一行只有一个属性类型,因此,属性类型后没有 ;(分号)
interface IPersonType {
name: String,
age: Number,
gender: String,
sing : (song : string) => void
run() : void
}
const obj : IPersonType = {
name : 'Tt',
age : 18,
gender : '女',
sing : (song) => {
console.log('我会' + song)
},
run() {
console.log('跑800m 3min');
},
}
obj.sing('小小小小小')
接口继承
interface实现继承 extends
- 如果两个接口之间有相同的属性或方法,可以将公共的属性或方法抽离出来,通过继承来实现复用
- 注意:不能调用可能是未定义的对象,所以调用时要加判断
stu1.sayHello && stu1.sayHello()
{
// interface定义对象 还可以实现继承
// 在ES6中 class类的继承使用extends关键字
// class People { }
// class Student extends People { }
// 人的类型接口
interface IPerson {
name: string,
age?: number,
sayHello?(): void
play?: () => void
}
// 学生的类型接口 继承于人的类型接口
interface IStudent extends IPerson {
grade: number
}
const stu1: IStudent = {
name: 'Tricia',
grade: 100,
sayHello() {
console.log('你好')
},
}
// 注意:不能调用可能是未定义的对象,所以调用时要加判断
// stu1.sayHello()
stu1.sayHello && stu1.sayHello()
}
type实现继承 & |
// 人的类型接口
type IPerson = {
name: string,
age?: number,
sayHello?(): void
play?: () => void
}
// 动物的接口
type IAnimal = {
eat(): void
}
// 学生的类型接口 继承于人的类型接口
type IStudent = {
grade: number
} & IPerson & IAnimal
type IWorker = {
} & IPerson | IAnimal
const stu1 : IStudent = {
name: 'Tricia',
grade: 100,
sayHello() {
console.log('你好')
},
eat() {
console.log('吃吃吃')
},
}
const worker : IWorker = {
eat() {
console.log('喝喝喝')
},
}
worker.eat()
stu1.sayHello && stu1.sayHello()
元组
元组: 特殊的数组 ---> 指定数组元素的类型 还要指定数组元素的个数
// 数组中只能有两个元素 且均为数字类型
let arr1 : [number, number] = [111, 222]
// 数组中只能有两个元素 为键值对
let arr2 : [string, number] = ['Tricia', 22]
类型推论
在 TS 中,某些没有明确指出类型的地方,TS 的类型推论机制会帮助提供类型
- 变量声明并赋值 推论
- 函数的返回值 推论
let num = 100
function fn (a: number, b: number) {
return a + b + ''
}
字面量类型
将一个固定的值设置为类型 这个就称为字面量类型,一般配合联合类型使用
// 字面量类型 将一个固定的值设置为类型 这个就称为字面量类型,一般配合联合类型使用
// str1 的类型为string str2的类型为 Hello
let str1 = 'haha'
const str2 = 'Hello'
// str2的完整写法: const str2: 'Hello' = 'Hello'
// 性别 只有两种
let gender : 'man' | 'woman'
gender = 'man'
枚举类型
如果没有提供默认值,从0开始递增。
数字枚举
// 枚举类型 如果没有提供默认值,从0开始递增
enum Drictions {
up,
down,
left = 88,
right
}
function changeDirection (dir : Drictions) {
console.log('方向改变' + dir)
}
changeDirection(Drictions.up)
changeDirection(Drictions.down)
changeDirection(Drictions.left)
changeDirection(Drictions.right)
字符串枚举
{
// 枚举类型 如果没有提供默认值,从0开始递增
enum Drictions {
up = '上',
down = '下',
left = '左',
right = '右'
}
function changeDirection (dir : Drictions) {
console.log('方向改变' + dir)
}
changeDirection(Drictions.up)
changeDirection(Drictions.down)
changeDirection(Drictions.left)
changeDirection(Drictions.right)
}
异构枚举
enum Drictions {
up = 10,
down = '下',
left = 88,
right
}
类型断言
有时候ts没有确定数据类型,我们可以使用类型断言明确一个数据类型
as后面加上明确的数据类型
// 获取一个类名叫.pic的img标签
const img = document.querySelector('.pic') as HTMLImageElement
console.log(img.src)
- 在前面使用
<>
// 获取一个div元素
const box = <HTMLDivElement> document.querySelector('div')
console.log(box.innerHTML)