1. 入门命令
1. 安装解析TS的工具包
- 打开VSCode终端
- 输入安装命令: npm i -g typescript
2. 执行TS文件步骤
第一种方法执行TS文件:
1. 在终端中输入 tsc + 文件名
(这时会生成一个js文件。比如:tsc hello.ts ==> hello.js)
2. 执行js: node hello.js
第二种执行TS文件(简化版):
1. 安装命令:npm i -g ts-node
(ts-node包内部将TS-->JS,然后,在执行JS代码)
2. 使用方式:ts-node hello.ts
2. 变量
1. 变量的使用
变量的使用有两种: 1. 先声明后赋值 2. 声明的同时并赋值
第一种:
// 1. 声明变量并指定类型
let age: number;
// 2. 赋值
age = 18;
第二种:
let age: number = 18;
2. 数据类型
TypeScript数据类型分为两大类:1. 原始数据类型(基本数据类型) 2. 对象类型(复杂数据类型)
常用的基本数据类型有:number/string/boolean/undefined/null
数字类型:
// 整数
let age: number = 18;
// 小数
let score: number = 99.9;
// 正数
let salary: number = 10000;
// 负数
let salary1: number = -2000;
字符串
字符串由零个或多个字符串串联而成的,用来表示文本信息
console.log('Hello Ts');
console.log('');
布尔类型
布尔类型的类型注解为:boolean
let isStudying: boolean = true;
let isStudying: boolean = false;
undefined、null
undefined:表示声明但未赋值的变量
let u: undefined
console.log(u) // 变量u的值为undefined
null: 表示声明了变量并已赋值,值为null
3. 运算符
- 加(+)、减(-)、乘(*)、除(/)
加法实现字符串拼接
// 规律:加号两边只要有一边是字符串,就执行字符串拼接
console.log(1 + 2) // 3
console.log(1 + ‘2’) // 12
- 加号引发的思考
console.log(2-'1') // 报错
console.log(2- +'1') // 1
注:在字符串面前添加 + 号,可以将string转化为number(字符串内容为数字时才有意义)
注:条件语句、循环语句等介绍省略。
4. 断点调试配置
第一步:准备调试的ts文件
第二步:添加调试配置
- 打开调试窗口:点击左侧活动栏倒数第二个按钮(debug)。
- 生成默认配置:点击DEBUG后面的下拉框,选择添加配置。
- 修改配置内容如下:
{
// 使用 IntelliSense 了解相关属性。
// 悬停以查看现有属性的描述。
// 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "调试ts代码",
"runtimeArgs": ["-r","ts-node/register"],
"args": ["${workspaceFolder}/02-datatype.ts"]
}
]
}
第三步:安装调试用到的包
- 在当前目录中,打开终端窗口。
- 在终端中输入以下命令:
npm i ts-node typescript
5. 数组
1. 创建数组的两种方式:
语法一(推荐):
let name: string[] = []
eg:
let name: string[] = ['迪丽热巴','古力娜扎','玛尔扎哈']
数组类型注解由两部分组成:类型+[]。此处表示字符串类型的数组(只能出现字符串类型)
语法二:
let name: string[] = new Array()
eg:
let name: string[] = new Array('迪丽热巴','古力娜扎','玛尔扎哈')
语法三(推荐):
let arr: Array<number> = [1,2,3,4]
补充元组(Tuple) 使用场景:比如某个数组我只让它有两个元素,再多添加就会报错。
let position: [number, number] = [39, 40]
2. 数组长度和索引
let foods: string[] = ['米饭', '馒头', '煎饼']
// 索引: 0 1 2
// 长度
console.log(foods.length) // 3
3. 取值
语法: 数组名称[索引]
let foods: string[] = ['米饭', '馒头', '煎饼']
console.log(foods[0]) // 米饭
4. 存值
语法: 数组名称[索引] = 新值
let foods: string[] = ['米饭', '馒头', '煎饼']
foods[1] = '包子'
console.log(foods) //['米饭', '包子', '煎饼']
5. 添加新元素
// 如果索引不存在,就表示添加元素
添加数组通用语法:数组名称[数组长度] = 新值
let foods: string[] = ['米饭', '馒头', '煎饼']
1. foods[3] = '面条'
2. foods[foods.length] = '面条'
console.log(foods) // ['米饭', '馒头', '煎饼', '面条']
6. 遍历数组
let foods: string[] = ['米饭', '馒头', '煎饼']
for(let i: number = 0; i < foods.length; i ++) {
console.log(foods[i]); // 米饭 馒头 煎饼
}
6. 联合类型
表示首先arr是个数组,这个数组可以出现number或者string类型
let arr: (number | string)[] = [1, '馒头', '煎饼']
如果把小括号去掉: 表示arr可以是number类型,又可以是string类型的数组
let arr: number | string[] = 123;
let arr: number | string[] = ['馒头', '煎饼'];
6. 函数
1. 基本使用
1. 声明函数
function sing() {
console.log('五环')
}
2. 调用函数
sing();
2. 形参和实参
1. 形参语法: 形参名称:类型注解
function sing(songName: string) {
console.log(songName)
}
2. 实参: 调用函数时传入的参数,放在调用函数的小括号中
sing('五环')
3. 函数返回值
函数返回值的作用:将函数内部计算的结果返回,以便使用该结果继续参与其他的计算
基本使用: 步骤:1.指定返回值类型 2.指定返回值
3.1 单独指定参数、返回值类型
// 函数返回的类型
function getSum(nums: number[]): number {
let sum: number = 0;
for(let i: number = 0; i < nums.length; i++) {
sum = sum + nums[i];
// 返回值
return sum;
}
}
let result: number = getSum([1, 3, 5]) + getSum([2, 4, 6])
3.2 同时指定参数、返回值类型
// 前面就是参数类型, 后面就是函数返回值的类型
**(num1: number, num2: number) => number**
const add:(num1: number, num2: number) => number = (num1, num2) => {
return num1 + num2;
}
3.3 void类型 函数无返回值,使用void作为函数返回值的类型
function greet(name: string): void {
console.log('hello' + name)
}
3.4 函数可选参数
- 可选参数:在参数后面加?
- 可选参数只能出现在参数列表的最后
function mySlice(start?: number, end?: number): void {
console.log('开始' + start, '结束' + end);
}
mySlice();
mySlice(1);
mySlice(1, 3);
4. 泛型
<T>
function sing<T>(songName: T):void {
console.log(songName)
}
sing<string>('abc')
sing<number>(123)
5. 变量作用域
变量可以分为两种: 1. 局部变量 2. 全局变量
局部变量:表示在函数内部声明的变量,该变量只能在函数内部使用。
function fn() {
let num: number = 1;
cnsole.log(num) // 1
}
console.log(num) //报错
全局变量:表示在函数外部声明的变量,该变量使用在任何地方
let num: number = 1;
function fn() {
cnsole.log(num) // 1
}
console.log(num) //1
7. 对象
1. 对象类型:
// sayHi(): void的写法跟sayHi: () => void;是一样的
let person:{name: string; age: number; sayHi(): void; greet(name: string): void} = {
name: 'ly',
age: 20,
sayHi() {}
}
1.1 对象的可选属性
function myMethod(config: {url: string; method?: string}) {
console.log(config);
}
myMethod({
url: 'XXXX'
})
1.2 接口和类型别名的区别
2. 对象的类型注解
TS中的对象是结构化的,在使用对象前,就可以根据需求,提前设计好对象的结构。
对象的结构化类型: 建立一种契约,约束对象的结构。
类型注解
//. 是冒号,不是等号。
let person : {
name : string; // 不是逗号,是分号。或者分号可以省略
age : number;
}
//. 是等号
person = {
name: '哈哈', // 是逗号
age: 18
}
3. 对象方法的类型注解
方法类型注解:1. 参数 2. 返回值
1. 无参数,无返回值
let person: {
sayHi: () => void
}
person = {
sayHi: function() {
XXXX
}
}
2. 有参数,无返回值
let person: {
sayHi: (name: string) => void
}
person = {
sayHi: function(name: string) {
XXXX
}
}
3. 有参数,有返回值
let person: {
sayHi: (num1: number, num2: number) => number
}
person = {
sayHi: function(num1: number, num2: number) {
return num1 + num2
}
}
4. 接口的使用
4.1 接口的使用 为对象的类型注解命名,并为你的代码建立契约来约束对象的结构
第一种语法:
创建接口
interface IUser {
name: string;
age: number
}
使用接口
let person: IUser = {
name: 'jack',
age: 18
}
第二种语法:implements
interface IPerson {
name: string;
age: number;
sex: string;
getName: () => string;
getAge: () => number;
}
使用接口
class Person implements IPerson {
name: string = '张三';
age: number = 18;
sex: string;
getName (): string {
return this.name
};
getAge (): number {
return this.age
};
}
4.2 接口的继承 通过extends关键字实现继承
interface PointA {
x: number;
y: number
}
interface PointB extends pointA {
z: number
}
let point1: PointB = {
x: 1,
y: 2,
z: 3
}
5. 对象数组中常用的一些方法
- push 返回值是数组的长度(添加到数组的末尾)
let animals = ['pigs', 'goats', 'sheep']
let count = animals.push('cows')
console.log(count) // 4
console.log(animals) //['pigs', 'goats', 'sheep', 'cows']
- forEach
let songs: string[] = ['五环', '探清水河']
songs.forEach(function(item, index)) {
console.log('元素', item,'索引', index)
}
- some
遍历数组,查找是否有一个满足条件的元素(如果有,就可以停止循环)
some方法的返回值:布尔值。如果找到满足条件的元素,结果为true;否则,为false.
let nums: number[] = [1, 12, 3]
let has: boolean = nums.some(function(num)) {
if(num > 10) {
return true
} else {
return false
}
}
console.log(has) // true(有比10大的数字)
只会执行两次,找到了就停止了。
6. TS类型推论说明
由于类型推论的存在,这些地方可以不写类型注解。
发生类型推论的两种场景: 1. 声明变量并初始化时 2.决定函数返回值时(即声明并且赋值,才会有类型推断)
可以省略:: number 因为赋值了18,类型推断就会推断出是number类型
let age: number = 18
不会发生类型推论的:
let age
age = 18
age = 'haha'
可以不写:返回值的类型: number,但是参数类型注解是要写的
function sum(num1: number,num2: number): number {
return num1 + num2
}
sum(1,2)
8. 浏览器中运行TS
注:浏览器中只能运行JS,无法直接运行TS,因此需要将TS转化为JS然后再运行。
浏览器中运行TS的步骤:
- 使用命令tsc index.ts 将ts文件转化成js文件
- 在页面中,使用script标签引入生成的js文件 (按照上述的步骤,如果修改了TS文件,就要执行一次tsc index.ts。才能看见修改过的页面)
问:每次修改TS文件后,都要重新运行tsc命令将ts转化为js???
解决方式:使用tsc命令的监视模式
tsc --watch index.ts
解释:--watch表示启用监视模式,只要重新保存了ts文件,就会自动调用tsc将ts转化为js
9. TS的类型断言
问题:
let img = document.querySelector('#img')
调用querySelector()通过id选择器获取DOM元素时,拿到的元素类型都是Element.
因为:无法根据id来确定元素的类型,所以该方法返回了一个宽泛的类型:元素(Element)类型。
导致的问题:无法访问img元素的src属性了。
因为:Element类型只包含所有元素共有的属性和方法(比如:id属性)。
解决方式:
使用类型断言,来手动指定更加具体的类型(此处应该比Element类型更加具体)
第一种语法:
值 as 更加具体的类型
let img = document.queerSelector('#img') as HTMLImageElement
将类型指定为HTMLImageElement
技巧:通过console.dir()打印DOM对象。来查看该元素的类型。
第二种语法:
<类型>值
let img = <HTMLImageElement>document.queerSelector('#img')
10. DOM操作
类样式的操作有三种:
// 添加类名
dom.classList.add('a','b')
// 删除类名
dom.classList.remove('b', 'c')
// 判断类名是否存在
dom.classList.contains('a')
函数声明事件处理程序
在函数声明形式的事件处理程序中,使用事件对象时,应该指定参数类型
btn.addEventListener('click', handleClick)
// 指定参数类型
function handleClick(event: MouseEvent){}
11. 枚举
使用场景: 当变量的值,只能是几个固定值中的一个,应该使用枚举实现。
注意: JS中没有枚举,这是TS为了弥补JS自身不足而新增的。
创建枚举的语法:
enum 枚举名称 {成员1, 成员2, ....}
eg:
enum Gender {Female, Male}
enum Player {X, O}
注: 约定枚举名称、成员名称以大写字母开头。 枚举中的成员,根据功能自己指定。 枚举中的成员不是键值对。
使用枚举
- 枚举是一种类型,因此可以其作为变量的类型注解。
enum Gender {Female, Male}
let userGender: Gender
- 访问枚举中的成员,作为变量的值:
userGender = Gender.Female // 0
userGender = Gender.Male // 1
userGender = Gender[0] // Female
userGender = Gender[1] // Male
就相当于:
enum Gender {
Female:0,
Male:1,
0: Female,
1: Male
}
- 枚举成员是只读的,也就是说枚举中的成员可以访问,但是不能赋值!
Gender.Female = '男' // 错误!
- 枚举成员中的值
问题: 将枚举成员赋值给变量,变量的值是什么呢?
数字枚举: 我们把枚举成员的值为数字的枚举,成为数字枚举。
字符串枚举
字符串枚举: 枚举成员的值都是字符串。
12. ts中的类
类:
calss实例方法的举例:
calss继承:
- 通过extends继承
- implements实现接口
public
protected
private
只能在类内访问到,自己的实力都访问不到。
13. 类型别名
当同一类型被多次使用时,简化该类型的使用
**使用type关键字创建类型别名**
type CustomArray = (number | string)[];
let arr:CustomArray = [1, 2, '你好']
let arr1:CustomArray = [2, 4, '哈哈']
14. 字面量类型
15. any类型
16.typeof的使用
17.类型兼容性说明
1.兼容性的说明
2. 对象之间的类型兼容
3. 接口之间的类型兼容
4. 函数之间的类型兼容
18. 交叉类型
交叉类型和接口之间的对比
19. 泛型
为什么使用泛型:
泛型的基本使用:
简化调用泛型函数:
泛型约束
- 指定更加具体的类型
- 添加约束
多个泛型变量的情况
泛型接口
泛型类
泛型工具类型Partial
将已有类型的转换成可选的类型,会生成一个新的类型
泛型工具类型ReadOnly
泛型工具类型Pick
泛型工具类型Record
20. 索引签名类型
21. 映射类型
- 映射类型keyof
- 理解泛型工具类型Portail的实现
22. 索引查询类型
- 同时查询多个
23.TS中的两种文件类型
第一点举例子:
- 内置类型声明文件
- 第三方库的类型声明文件
24. React中使用TS
已有项目中使用TS:
使用TS后跟之前单独写react有什么不同:
tsconfig.json的说明:
25. React函数组件
- 函数组件的类型
- 函数组件默认值
- 事件和事件类型
- 类组件的类型(组件类型)
- 类组件的类型(组件属性)
- 类组件的类型(状态和事件)