1、TypeScript 环境安装与运行
Typescript中文文档: https://typescript.bootcss.com/functions.html
1.1 TypeScript 环境安装
全局安装 TypeScript : npm install -g typescript
校验 TypeScript是否安装成功: tsc -v
tsc的作用:负责将 ts 代码 转为 游览器 和 nodejs 识别的 js代码
1.2 TypeScript 运行
- 在后缀名为 的文件中书写 typescript 代码
- 使用 tsc 将 typescript 代码编译成 js 代码
- 在游览器或者 nodejs 中执行 js 代码
自动编译
1、运行 tsc --init ,创建 tsconfig.json 文件
2、修改 tsconfig.json 文件,设置 js 文件夹:"outDir": "./js/"
3、设置 vscode 监视任务
ts和 js的区别
ts提供了更丰富的语法提示;
ts在编译阶段能够检查错误; js是在执行阶段才检查的错误;
ts是静态类型; js是动态类型;
js
let test = "123"
test = 123 // js动态类型,可以随意改变变量类型,这里就把string类型改成了number类型
ts
let test = "123"
test = 123 -------这行代码会报错,警告:不能将类型“number”分配给类型“string”。
数据类型
JS数据类型
原始数据类型: boolean string number null undefined symbol
引用数据类型:object
TS数据类型
基础类型:boolean string number null undefined symbol any never void
接口: interface
数组 number[] string[] boolean[] 泛型的写法: Array<number>
新的语法特性:
as 断言
class (OOP 面向对象的三大特性)︰封装,继承,多态;
2、TypeScript 变量与数据类型
在 javaScript 弱类型语言,在申明变量时直接赋值就行,当 JS 引擎 运行的时候,会根据等号后面的值自动给变量赋值对应的类型
let 变量名 = 值;
let name = "zhangsan"; //默认为 String 类型
let num = 18;//默认为 Number 类型
ley obj = {};//默认为 Object 类型
而在 typeScript 中,变量申明时必须指定变量类型,一旦为变量指定类型后,就只能给这个变量设置相同类型的值
typeScript中声明变量时,在变量名后面加上一个冒号,再加上变量类型就行了。
let 变量名: 变量类型 = 值;
let name: string = "张三";
let num: number = 18;
TypeScript 数据类型 | 常见类型,声明时需要指定变量类型(语法如下)
//1、字符串类型 '' 、 "" 、 ``
let aName: string = "秀儿";
// 2、数值类型
let aAge: number = 18;
aAge = 18.5;
aAge = -18;
// 3、布尔值类型 true / false
let isDog: boolean = true;
isDog = false;
// 4、undefined 和 null
let undef: undefined = undefined;
let nul: null = null;
TypeScript 数据类型 | 字面量,限制变量的值就是 字面量的值 本身(语法如下)
let num: 10;
num只能等于 10,num如果赋值11的话会报错
num = 10;
let gender: ""mela" | "person";如果联合申明的话
这个 gender变量的值可以是 mela,也可以是 person,但不能等于别的值
gender = "mela";
我们可以给类型取个别名,在给变量设置类型的时候,赋值类型别名就行,语法如下
type 类型别名 = 类型;
TypeScript 数据类型 | object
缺点:如果只给变量指定 object 类型的话,由于 js 万物皆对象,变量设置 object 类型却没有给变量添加什么限制(例如)
oject 表示非原始类型
let obj: object;
obj = {};
obj = function(){};
obj = new Date();
obj = new Array();
obj = [];
我们一般限制对象类型的时候不是为了限制他是不是一个对象,而是为了限制对象的属性,所以在TS中一般不使用 object 声明变量,而是用 {} 来指定对象中可以包含那些属性,语法如下
语法:{ 属性名: 属性值, 属性名: 属性值 };
通过对象的属性限制对象
在属性名后面加上问号,表示是可选可不选属性(以下两种对象赋值都不会出错,但是如果没有问号,第一种方式会报错)
let obj01: { name: string, age?: number };
obj01 = { name: "LBipanda" };第一种
obj01 = { name: "LBipanda", age: 18 };
但是这样会有一个缺点,每次声明变量你都要已知对象的有多少属性,如果不确定对象有多少属性,可以使用以下方法
[propName: string]: any 代表任意类型和数量的属性,如下,你可以写 age,height
propName 只是一个变量名,你写什么都行 例如 xxx、a、b
let myself: { name: string, [propName: string]: any};
myself = { name: "LBipanda", age: 18, height: 178 };
还有一个业务场景,有一个变量 d,我需要他是一个函数,并且限制他的的参数类型和数量和返回值
设置函数结构的类型声明,语法如下
语法:(形参: 类型, 形参: 类型, ...) => 返回值类型
如果不想限制形参类型和数量的话可以这样
语法:(形参: 类型, 形参: 类型, ...形参: any[]) => 返回值类型
限制了形参类型和数量
let a: (a: number, b: number) => number;
a = function(height: number, weight: number): number{
return height * weight;
}
console.log(a(10,20)) ==》打印值 200
不限制形参类型和数量
let func: (...xxx: any[]) => string;
func = function(name: string, age: number, alone: boolean): string{
let tempAlone = alone?"孤独":"不孤独";
return "姓名:" + name + ", 年龄:" + age + "岁,是否孤独:" + tempAlone;
}
console.log(func("李彬", 18, true))
TypeScript 数据类型 | 数组,声明时需要指定 (语法如下)
特点:
1、元素类型 固定
2、长度不限制
方式一: let 数组名: 类型[];
let arr1: string[] = [ "亚瑟王", "鲁班", "大乔" ];
let arr2: (string | number)[] = [ "亚瑟王", 22, "大乔", 999]
方式二:let 数组名: Array<类型>;
let arr3: Array<string> = [ "亚瑟王", "鲁班", "大乔" ];
let arr4: Array<(string | number)> = [ "张三", 55, "王五", 999]
TypeScript 数据类型 | 元组(tuple)
概念:就是一个规定了 的 "数组" 而每个元素的类型,可以不相同
特点:
1、声明时,要指定元素个数
2、声明时,要为每个元素规定 类型
为什么要有元组?
TS 中数组元素类型必须一致,如需要不同元素,可以用 了!
理解:元组(tuple):就是一个已知的数组,内部的元素类型 不必相同。(语法如下)
let 元组名: [类型1, 类型2, 类型3] = [ 值1, 值2, 值3 ];
let tup1: [string, number, boolean];
tup1 = ["LBipanda", 18, true];
//访问 元组 中的元素 和长度,还是和 js 一样,通过 [下标]的方式获取元组的元素,通过.length的方式获取元组长度
console.log(tup1[0]);
console.log(tup1.length);
TypeScript 数据类型 | 枚举(enum)
枚举(enum):用一组标识 来代表 数值。
枚举项:一般用英文和数字,而 枚举值 用整型数字
申明语法 枚举名首字母要大写
enum 枚举名{
枚举项1 = 枚举值1,
枚举项2 = 枚举值2,
枚举项3 = 枚举值3,
... = ...
}
// 创建性别枚举类
enum Gender {
Boy = 1,
Girl = 2,
Unknow = 3,
}
console.log("enum",Gender.Boy)//1
console.log("enum",Gender.Girl)//2
console.log("enum",Gender.Unknow)//3
// 使用性别枚举
let userSex: Gender = Gender.Boy;
console.log("userSex",userSex)//1
使用默认枚举值
enum 枚举名{
枚举项1,
枚举项2,
枚举项3,
......
}
enum GunTypeTwo{
M416,// ==>0
Ak47,// ==>1
Goza,// ==>2
}
TypeScript 数据类型 | 任意类型(any)
概念:any 代表任意类型,一般在获取 DOM 时使用
let name: any; 显示的 any,声明变量指定类型 any,name可以赋任意类型的值
name = "zhangsan";
name = 18;
name = true;
let people; 隐示申明类型 any,声明变量不指定类型,TS解析器会自动判断变量类型为 any
people = "lisi";
people = 18;
people = true;
any 类型的缺点:可以给任意类型的变量赋值,这样会关闭其他变量的 TS 类型检测。
let name: any;
name = "zhangsan";
name = 18;
name = true; 这个时候 name 的值是 boolean 类型
let item: string; item变量的类型是 string 类型
item = name; item 按理说只能赋值 string 类型的值,但是 name 的值是 boolean 类型,但是 name 能赋值成功给 item。
所以一般建议用 unknown 代替 any 使用,unknown 表示未知类型的值
TypeScript 数据类型 | unknown
概念:unknown 实际上就是一个类型安全的 any
特点:
1、unknown 类型的变量,可以赋任何类型的值。
2、unknown 类型的变量,不能直接赋值给其他变量。直接赋值会报错
1、unknown 类型的变量,可以赋任何类型的值
let gun: unknown;
gun = "m416";
gun = 222;
gun = false;
如果 unknown 类型的变量想赋值给其他类型的变量有以下几种方法:
let bbb: unknown;
bbb = "lisi";
bbb = 22;
let c: string;
第一种 先进行类型检查再赋值
if(typeof(bbb) === "string"){
c = bbb;
}
第二种 通过类型断言的方式赋值
类型断言的作用:类型断言可以用来告诉解析器变量的实际类型
语法:
1、变量 as 类型
2、<类型> 变量
c = bbb as string;
c = <string> bbb;
我们在接收客户输入 或 第三方代码库时,还不能确定会返回什么类型的值时,此时可以使用 any 类型。
示例:
let txtName: any = document.getElementById("txtN");
TypeScript 数据类型 | void
概念:void 代表 空,一般用在无返回值的函数。(在 TS 中,函数有返回值,需要指定返回值类型)
有返回值
function sayHi1(): string{
return "hi,你好呀………………";
}
let re1 = sayHi1();
无返回值
function sayHi2(): void{
console.log("hi,你好呀………………");
}
sayHi2();
TypeScript 数据类型 | never
概念:never 代表 没有返回值,常用于 作为抛出异常 或 无限循环的 函数返回类型
无限循环
function test(): never{
while(true){
}
}
抛出异常
function test2(): never{
throw new Error("抛出异常");
}
补充:never 类型是 ts 中的底部类型,所有类型都是 never 类型的 父类。所以 never 类型值 可以赋给任意类型的变量
let x: never = test();
let y: never = test();
TypeScript 类型注解 、 类型推断
类型推断概念:如果变量的声明和初始化是在同一行,可以省略掉变量类型的声明.
类型注解
let 变量名: 变量类型 = 值;
let num: number = 11
let name: string = "LBipanda"
类型推断
let 变量名 = 值; 相当于 let 变量名: 变量类型 = 值;
验证:
let age = 18;//此时变量 age 的类型推断为 number
age = "jack";//报错,因为变量 age 的类型是 number
TypeScript 数据类型 | 联合类型
概念:如表示值可以取多种类型中的一种.
let 变量名: 变量类型1 | 变量类型2 = 值;
注意:
1.联合类型的共有属性是不会报错;
2.在赋值的时候确认类型;
//1.联合类型的共有属性是不会报错;
people = "LBipanda"
console.log(people.length);
people = 18
console.log(people.length);//报错,类型“number”上不存在属性“length” 2.在赋值的时候确认类型;
TypeScript 数据类型 | 交叉类型(&)
交叉类型是将多个类型合并为一个类型, 表示"并且"的关系,用&连接多个类型, 常用于对象合并:
interface A {a:number};
interface B {b:string};
const a:A = {a:1};
const b:B = {b:'1'};
const ab:A&B = {...a,...b};
3、TypeScript 函数
函数的定义
1、基本的函数定义
1、函数声明
function addd(x: number, y: number): number{
return x+y
}
2、函数表达式
let add: (x: number, y: number) => number = function(x, y) { //es5
return x+y;
};
let add1: (x: number, y: number) => number = (x, y) => { //es6
return x+y;
};
console.log(add(1,2))
console.log(add1(2,3))
2、使用接口定义函数
interface Add {
(x: number, y: number): number
}
let myFunc: Add = function(x, y){ //es5
return x+y;
};
let myFunc1: Add = (x, y) => { //es6
return x+y;
};
console.log(myFunc(3,6));
console.log(myFunc(6,4));
3,使用类型别名来定义函数:
类型别名使用type关键字,相当于为函数类型起一个名字
type Add = (x: number, y: number) => number
let add1: Add = function(x, y){ // es5
return x + y
}
let add2: Add = (x, y) => { // es6
return x + y
}
3.1、函数 返回值类型
function 函数名():返回值类型{//如果函数没有返回值的话,则定义为 void
}
let 变量名:变量类型 = 函数名();//变量类型必须和函数的返回值一样
function sayHi(): string{
return "hello world";
}
let res1: String = sayHi();
console.log(res1);
3.2、函数 形参 实参 类型
实参和 形参 的类型必须要一致
实参和 形参 的数量必须要一致
functio 函数名(形参1:类型, 形参2:类型):返回值类型{
}
let 变量名: 变量类型 = 函数名(实参1, 实参2);
function person(name: string, age: number): void{
console.log(`你好,我叫${name},我今年${age}岁了`);
}
person("Lbipanda",18);
小结
- 函数必须定义 ,如果没有返回值,则定义返回值类型为
- 实参 和形参 的要一致
- 实参 和形参 的要一致
3.3、函数 可选参数
function 函数名(形参 ?: 类型):返回值类型 {
}
调用:
可选参数可以传实参也可以不传
不传递实参 ==》 函数名();
传递实参 ==》 函数名(实参值);
function sayNo(name ?: string):void{
console.log(`${name || XXX},你在说什么`);
}
sayNo(); ===>XXX,你在说什么
sayNo("Lbipanda"); ===>Lbipanda,你在说什么
注意
3.4、函数 默认值
function 函数名(形参1:类型 = 默认值1, 形参2: 类型 = 默认值2): 返回值类型{
}
调用:
不传实参 函数(); == 编译后 ==》函数名(默认值1, 默认值2):
传一个实参 函数(实参1); == 编译后 ==》函数名(实参1, 默认值2):
传两个实参 函数(实参1, 实参2); == 编译后 ==》函数名(实参1, 实参2):
如果我想跳过第二个参数,只传第二个参数
函数(undefined, 实参 2); == 编译后 ==》函数名(默认值1, 实参2):
function timi(name: string = "缘妙不可言", count: number = 1): void{
console.log(`Timi,${name} 召唤师打了 ${count} 把游戏。`);
}
timi(); ===》Timi,缘妙不可言 召唤师打了 1 把游戏。
timi("北港不夏"); ===》Timi,北港不夏 召唤师打了 1 把游戏。
timi("北港不夏",3); ===》Timi,北港不夏 召唤师打了 3 把游戏。
timi(undefined,5); ===》Timi,缘妙不可言 召唤师打了 5 把游戏。
3.5、函数 剩余参数
特点:
1、剩余参数 只能 定义一个
2、剩余参数 只能 定义为数组
3、剩余参数 只能 定义在形参列表最后
如果剩余参数不确定什么类型写 ...形参: any[]
function 函数名(形参1: 类型, 形参2: 类型, ...形参3: 类型[]):返回值类型 {
}
function add(a: number, b: number,...restOfNum: number[]){
let ret = a + b;
for(let i of restOfNum){
ret += i;
}
console.log(ret)
}
add(1,2,3,4,5,6,7,8,9,10); ===》 55
3.5、函数重载
同名函数的参数的个数、类型或者顺序必须不同(其中有一个不一样就满足条件了) 叫函数的重载
重载允许一个函数接受不同数量或类型的参数时,作出不同的处理。 为同一个函数提供多个函数类型定义来进行函数重载
在定义重载的时候,一定要把最精确的定义放在最前面。因为查找重载列表,会从第一个重载定义开始使用,如果匹配成功的话就使用,否则就继续向下查下;最后函数实现时,需要使用 |操作符或者?操作符,把所有可能的输入类型全部包含进去(不确实的话可以写any)
函数重载的意义在于能够让你知道传入不同的类型参数得到不同的类型结果,如果传入的参数不同,但是得到的结果(类型)却相同,那么这里就不需要使用函数重载
现在有这样一个需求: 我们有一个add函数,它可以接收string类型的参数进行拼接,也可以接收number类型的参数进行相加
下面是按照之前我们所学知识写的代码
function add(arg1: string | number, arg2: string | number): number | string{
if (typeof arg1 === 'string' && typeof arg2 === 'string') {
return arg1 + arg2;
} else if (typeof arg1 === 'number' && typeof arg2 === 'number') {
return arg1 + arg2;
}
}
let a1 = add(1, 2);
let a2 = add('a', 'b');
上面的代码在调用函数的时候,定义的变量a1和a2没有去定义类型,只是用了根据等号右边的值去赋值给左边的变量,事实上,a1和a2也不能去指定为string或者number,因为add函数的返回值就是一个联合类型number | string,所以是实际工作中如果发生了这种事情,会导致a1和a2使用变得非常混乱,接下来我们使用函数重载的形式对代码进行优化
先进行函数的重载,定义函数,将参数和返回值的类型定死
function add(arg1: string, arg2: string): string;
function add(arg1: number, arg2: number): number;
接下来进行函数的实现
function add(arg1: string | number, arg2: string | number): number | string{
if (typeof arg1 === 'string' && typeof arg2 === 'string') {
return arg1 + arg2;
} else if (typeof arg1 === 'number' && typeof arg2 === 'number') {
return arg1 + arg2;
}
}
let a1 = add(1, 2);
let a2 = add('a', 'b');
这时候就可以明确a1和a2的类型了,a1是number类型,a2是string类型
注意,function add(arg1: string | number, arg2: string | number): number | string并不是重载列表的一部分,因此这里只有两个重载:一个是接收数字,另一个接收字符串。 以其它参数调用会产生错误