还有一些没有写完,还在学习中。
目录
一、TypeScript是什么?
TypeScript简称TS
TS和JS之间的关系其实就是Less/Sass和CSS之间的关系
就像Less/Sass是对CSS进行扩展一样, TS也是对JS进行扩展
就像Less/Sass最终会转换成CSS一样, 我们编写好的TS代码最终也会换成JS
二、体验TypeScript
1.JS会出现的问题
let value;
value = 123;
value = '123';
value = true;
value = [1,2,3];
由于JavaScript是弱类型语言,所以只要定义了一个变量, 就可以往这个变量中存储任意类型的数据
也正是因为如此, 所以会给我们带来一个问题。
如一个函数,我们期待参数a是一个数组,参数b是一个数值
function test(a, b) { // 期望a是一个数组, b是一个数值
return a.length + b;
}
// let res = test([1, 3, 5], 10); // 没有问题 返回13
let res = test(1, 10); // 出现问题 返回NaN
console.log(res);
2.TS解决JS的问题
想要使用TS,需要先安装TS。
npm install typescript -g
1.安装完成后,会发现多安装了一个tsc的工具,这个工具是编译工具,把TS编译成JS文件。
2. 创建一个TS文件,TS支持类型注解,所以可以通过类型注解来告诉系统,变量储存的类型
3.解决JS的问题
运行TS文件之前,需要对TS进行编译,用刚刚安装的tsc进行编译。编译完成会生成JS文件然后执行JS得到结果13
若参数类型传入错误,会报错。也不会通过 编译。
三、TypeScript基本类型
1.数值类型Number
let val1:number; // 定义了一个名称叫做val1的变量, 这个变量中将来只能存储数值类型的数据
val1 = 123;
val1 = "123"; // 会报错
注意点: 其它的用法和JS一样
2.布尔类型Boolean
let val2:boolean;
val2 = true;
val2 = 1; // 会报错
3.字符串类型String
let val1:number;
val1 = 123;
let val2:boolean;
val2 = true;
let val3:string;
val3 = "123";
val3 = `val1=${val1}, val2==${val2}`;
//结果为val1=123, val2==true
4.数组和元组和联合类型
一、数组类型
方式一
要求定义一个数组, 这个数组中将来只能存储数值类型的数据
let arr1:Array<number>; 表示定义了一个名称叫做arr1的数组, 这个数组中将来只能够存储数值类型的数据
arr1 = [1, 3, 5];
arr1 = ['a', 3, 5]; 报错
方式二
要求定义一个数组, 这个数组中将来只能存储字符串类型的数据
let arr2:string[]; 表示定义了一个名称叫做arr2的数组, 这个数组中将来只能够存储字符串类型的数据
arr2 = ['a', 'b', 'c'];
arr2 = [1, 'b', 'c']; 报错
二、联合类型
let arr3:(number | string)[];表示定义了一个名称叫做arr3的数组, 这个数组中将来既可以存储数值类型的数据, 也可以存储字符串类型的数据
arr3 = [1, 'b', 2, 'c'];
arr3 = [1, 'b', 2, 'c', false]; 报错
三、任意类型
let arr4:any[]; 表示定义了一个名称叫做arr4的数组, 这个数组中将来可以存储任意类型的数据
arr4 = [1, 'b', false];
四、元祖类型
TS中的元祖类型其实就是数组类型的扩展
元祖用于保存定长定数据类型的数据
let arr5:[string, number, boolean]; 表示定义了一个名称叫做arr5的元祖, 这个元祖中将来可以存储3个元素, 第一个元素必须是字符串类型, 第二个元素必须是数字类型, 第三个元素必须是布尔类型
arr5 = ['a', 1, true];
arr5 = ['a', 1, true, false]; // 超过指定的长度会报错
arr5 = ['a', 1, true];
5.枚举类型
枚举类型是TS为JS扩展的一种类型, 在原生的JS中是没有枚举类型的
枚举用于表示固定的几个取值
enum Gender{ // 定义了一个名称叫做Gender的枚举类型, 这个枚举类型的取值有两个, 分别是Male和Femal
Male,
Femal
}
let val:Gender; // 定义了一个名称叫做val的变量, 这个变量中只能保存Male或者Femal
val = Gender.Male;
val = Gender.Femal;
val = 'nan'; // 报错
val = false;// 报错
注意点: TS中的枚举底层实现的本质其实就是数值类型, 所以赋值一个数值不会报错
val = 666; // 不会报错
console.log(Gender.Male); // 0
console.log(Gender.Femal);// 1
注意点: TS中的枚举类型的取值, 默认是从上至下从0开始递增的
虽然默认是从0开始递增的, 但是我们也可以手动的指定枚举的取值的值
注意点: 如果手动指定了前面枚举值的取值, 那么后面枚举值的取值会根据前面的值来递增
console.log(Gender.Male); // 6
console.log(Gender.Femal);// 7
注意点: 如果手动指定了后面枚举值的取值, 那么前面枚举值的取值不会受到影响
console.log(Gender.Male); // 0
console.log(Gender.Femal);// 6
注意点: 我们还可以同时修改多个枚举值的取值, 如果同时修改了多个, 那么修改的是什么最后就是什么
console.log(Gender.Male); // 8
console.log(Gender.Femal);// 6
我们可以通过枚举值拿到它对应的数字
console.log(Gender.Male); // 0
我们还可以通过它对应的数据拿到它的枚举值
console.log(Gender[0]); // Male
探究底层实现原理
var Gender;
(function (Gender) {
// Gender[key] = value;
Gender[Gender["Male"] = 0] = "Male";
Gender[Gender["Femal"] = 1] = "Femal";
})(Gender || (Gender = {}));
let Gender = {};
Gender["Male"] = 0;
Gender[0] = "Male";
Gender["Femal"] = 1;
Gender[1] = "Femal";
6.void和any类型
// any类型
// any表示任意类型, 当我们不清楚某个值的具体类型的时候我们就可以使用any
// 一般用于定义一些通用性比较强的变量, 或者用于保存从其它框架中获取的不确定类型的值
// 在TS中任何数据类型的值都可以负责给any类型
// let value:any; // 定义了一个可以保存任意类型数据的变量
// value = 123;
// value = "abc";
// value = true;
// value = [1, 3, 5];
// void类型
// void与any正好相反, 表示没有任何类型, 一般用于函数返回值
// 在TS中只有null和undefined可以赋值给void类型
function test():void {
console.log("hello world");
}
test();
let value:void; // 定义了一个不可以保存任意类型数据的变量, 只能保存null和undefined
// value = 123; // 报错
// value = "abc";// 报错
// value = true;// 报错
// 注意点: null和undefined是所有类型的子类型, 所以我们可以将null和undefined赋值给任意类型
// value = null; // 不会报错
value = undefined;// 不会报错
7.类型断言
1.什么是类型断言?
TS中的类型断言和其它编程语言的类型转换很像, 可以将一种类型强制转换成另外一种类型
类型断言就是告诉编译器, 你不要帮我们检查了, 相信我,我知道自己在干什么。
例如: 我们拿到了一个any类型的变量, 但是我们明确的知道这个变量中保存的是字符串类型
此时我们就可以通过类型断言告诉编译器, 这个变量是一个字符串类型
此时我们就可以通过类型断言将any类型转换成string类型, 使用字符串类型中相关的方法了
let str:any = 'lx666';
方式一
let len = (<string>str).length;
方式二
推荐使用as来进行类型转换(类型断言)因为第一种方式有兼容性问题, 在使用到了JSX的时候兼容性不是很好
let len = (str as string).length;
console.log(len);
四、TypeScript接口
1.接口
什么是接口类型?
和number,string,boolean,enum这些数据类型一样,
接口也是一种类型, 也是用来约束使用者的
定义一个接口类型
interface FullName{
firstName:string
lastName:string
}
let obj = {
firstName:'Liu',
lastName:'BuBu'
// lastName:18
};
需求: 要求定义一个函数输出一个人完整的姓名, 这个人的姓必须是字符串, 这个人的名也必须是一个字符
function say({firstName, lastName}:FullName):void {
console.log(`我的姓名是:${firstName}_${lastName}`);
}
say(obj);
2.可选属性
interface FullName {
firstName:string,
lastName:string,
middleName:string
}
function fn({firstName,lastName,middleName}:FullName):void{
if(middleName){
console.log(`我的名字是${firstName}_${middleName}_${lastName}`);
}else{
console.log(`我的名字是${firstName}_${lastName}`);
}
}
fn({firstName:'Liu',lastName:'BuBu',middleName:'666'})// 没有任何问题
fn({firstName:'Liu',lastName:'BuBu'}) // 报错
//如果使用接口来限定了变量或者形参, 那么在给变量或者形参赋值的时候,
//赋予的值就必须和接口限定的一模一样才可以, 多一个或者少一个都不行
//在开发过程中,想要少传入一个或多个参数应该怎么做?
可以将接口这样写:
interface FullName = {
firstName:string,
lastName:string,
middleName?:string
}
fn({firstName:'Liu',lastName:'BuBu',middleName:'666'})// 没有任何问题
fn({firstName:'Liu',lastName:'BuBu'}) //没有任何问题
3.索引签名
// 1.什么是索引签名?
// 索引签名用于描述那些“通过索引得到”的类型,比如arr[10]或obj["key"]
interface FullName {
//只要key和value满足索引签名的限定即可, 无论有多少个都无所谓
[propName:string]:string
}
function fn({firstName,middleName,lastName}:FullName):void {
// console.log(`我的名字是${firstName}_${lastName}`);
if(middleName){
console.log(`我的名字是${firstName}_${middleName}_${lastName}`);
}else{
console.log(`我的名字是${firstName}_${lastName}`);
}
}
fn({firstName:'Liu', lastName:'BuBu',middleName:'666',123:'123'})// 没有任何问题 注意满足接口的限定
4.只读属性
interface FullName{
firstName:string,
lastName:string
}
let myName:FullName = {
firstName: 'Liu',
lastName: 'BuBu'
};
myName.lastName = 'Xin';
console.log(myName);// 没有任何问题
//让对象属性只能在对象刚刚创建的时候修改其值 这就是只读属性
interface FullName{
firstName:string,
lastName:string
}
let myName:FullName = {
firstName: 'Liu',
readonly lastName: 'BuBu'
};
myName.lastName = 'Xin';
console.log(myName);// 编译不通过
5.函数接口
// 函数接口
// 我们除了可以通过接口来限定对象以外, 我们还可以使用接口来限定函数
interface fun{
(x:number,y:number):number
}
let sum:fun = function(x:number,y:number){
return x + y
}
console.log(sum(10,20)) //没有任何问题
6.混合接口
// 混合类型接口
// 约定的内容中既有对象属性, 又有函数
// 要求定义一个函数实现变量累加
interface fn{
():void,
count:number
}
//fn这个混合接口需要要求的是数据既要是一个没有参数没有返回值的函数
又要是一个拥有count属性的对象
fn作为函数的时候符合接口中函数接口的限定 ():void
fn作为对象的时候符合接口中对象属性的限定 count:number
let getCount = (function():fn{
let fun = function(){
fun.count++
console.log(fun.count)
}
fun.count = 0
return fun
})()
getCount() //1
getCount() //2
getCount() //3
7.接口的继承
// 接口的继承
// TS中的接口和JS中的类一样是可以继承的
interface LengthInterface {
length:number
}
interface WidthInterface {
width:number
}
interface HeightInterface {
height:number
}
interface RectInterface extends LengthInterface,WidthInterface,HeightInterface {
// length:number
// width:number
// height:number
color:string
}
let rect:RectInterface = {
length:10,
width:20,
height:30,
color:'red'
}
五、TypeScript函数
1.函数的声明和重载
// TS函数声明
// 先声明一个函数
type fn = (a:number,b:number) => number
// 再根据声明去实现这个函数
let addSum:fn = function (x,y) {
return x + y
}
console.log(addSum(10, 12));
// TS函数重载
// 函数的重载就是同名的函数可以根据不同的参数实现不同的功能
// 定义函数的重载
function getArr(a:number):number[]
function getArr(a:string):string[]
// 实现函数的重载
function getArr(a:any):any {
if (typeof a == "number"){
let brr = []
for (let i = 0; i < a; i++){
brr.push(i)
}
return brr
}else{
console.log(a.split(' '));
return a.split('')
}
}
let res = getArr('www.baidu.com')
console.log(res);
2.可选参数默认参数和剩余参数
// 可选参数
function add(x:number, y:number, z?:number):number {
return x + y + (z ? z : 0);
}
// let res = add(10, 20);
let res = add(10, 20, 30);
console.log(res);
// 默认参数
function add(x:number, y:number=10):number {
return x + y;
}
// let res = add(10);
let res = add(10, 30);
console.log(res);
// 剩余参数
function add(x:number, ...ags:number[]) {
console.log(x);//10
console.log(ags);//[20,30,40,50]
}
add(10, 20, 30, 40, 50)