一、TS初识
//TS文件代码
(()=>{
function printStr(str:string){
return '你好'+str;
}
let str = 'learn cool';
console.log(printStr(str));
})
//1、将ts文件通过在HTML文件中通过script标签引入
//2、通过tsc tab键编译ts文件 生成的js文件
//编译后的JS文件代码
(function () {
function printStr(str) {
return '你好' + str;
}
var str = 'learn cool';
console.log(printStr(str));
});
ts文件编译成js代码的区别
- 1、ts文件中可以写js的代码
- 2、ts中的类型定义在编译成js后消失
- 3、ts变量中使用let 定义,编译成js文件后变成var声明;
1.1vscode 可以自动编译ts代码
//1、执行tsc --init生成tsconfig.json
//2、修改config 文件outDir为./js
//3、打开终端、运行所有任务,监视ts
//4、创建ts文件自动生成js,创建html文件引入js文件,写ts代码
二、类型注解(约束函数、变量的)
类型注解:是一种轻量级的为函数或者变量添加的约束
- 如果定义的是什么类型 那么传入的参数就必须是什么类型;
(()=>{
function showMsg(str:String){
return str+'nihao'
}
// let str = 'xiao';
// console.log(showMsg(str));
let str = [1,2,3,4,5];
console.log(showMsg(str));
//1、首先当定义的参数类型为什么的时候就必须传入什么类型的参数,否则报错
console.log(showMsg());
//2、其次当定义时有参数传入时 就必须传入参数,否则会报错
//3、这两种情况在js文件中并不会报错,是因为js属于弱类型语言
})()
三、接口
1、接口:是一种能力一种约束而已;
2、ts文件中会实时对代码进行语法分析,即使告诉我们语法是否有误
// 接口:是一种能力一种约束而已
(()=>{
interface Iperson {
firstName:String,
lastName:String
}
function showFullName(person:Iperson){
return person.firstName +'_'+ person.lastName
}
// 定义一个person 变量
let person = {
firstName:'东方',
lastName:'不败'
}
console.log(showFullName(person));
})()
四、类
(()=>{
interface Iperson{
firstName:String,
lastName:String
}
//定义一个类
class Person{
firstName:string
lastName:string
fullName:string
//定义一个构造函数
constructor(firstName:string,lastName:string){
// 更新属性数据
this.firstName = firstName;
this.lastName = lastName;
this.fullName = this.firstName+"_"+this.lastName
}
}
// 定义个函数
function showFullName(person:Iperson){
return person.firstName+"-"+person.lastName;
}
// 通过类实例化一个对象 传进去的是一个对象
let person = new Person('诸葛','孔明')
console.log(showFullName(person));
})()
五、使用webpack打包TS
六、TS语法的学习
6.1基本数据类型
- ts与js类似,无非就是在变量名后面加上了数据类型;
let str:string = '小明';
let num:number = 1000;
let flag:boolean = true;
总结:ts中变量一开始是什么类型,那么后期赋值的时候也只能用这个类型的数据,是不允许用其他类型的数据赋值给当前的这个变量的;如:let str:string = ‘真香’ str = 50,没有武德(不允许)
//布尔类型
let flag:boolean = true;
// flag = 10;
console.log(flag);
//数字类型
let num:number = 10;
// num = '哈哈'
console.log(num)
//字符类型
let str1:string = '床前明月光';
let str2:string = '疑似地上霜';
let str3:string = '举头望明月';
let str4:string = '低头思故乡';
let str = `${str1},${str2},${str3},${str4}`;
console.log(str)
//字符数字组合
let num1:number = 1000;
let str5:string = '我现在有多少万元';
let res = str5+num1;
console.log(res)
//null、undefined
let und:undefined = undefined;
let nul:null = null;
console.log(und,nul);
//undefined和null都可以作为其他类型的子类型,把undefined和null赋值给其他类型的变量,如number类型的变量
let num6:number = undefined;
let num7:number = null;
console.log(num6,num7);
//1、数组类型
//1.1数组的定义
let arr1:number[] = [1,2,3,4,12];
console.log(arr1);
//1.2泛型的定义
let arr2:Array<number>=[100,20,30]
console.log(arr2);
//元祖类型
let arr3:[string,number,boolean] = ['小明',100.124,true];
console.log(arr3[0].split(''))
console.log(arr3[1].toFixed(2))
console.log('=======enum 枚举');
enum Color{
red=1,
green,
blue
}
let color:Color=Color.red;
console.log(color);
//根据编号可以查到对应的值,根据值能获取对应的编号,默认从0开始,依次递增1;
console.log(Color.red,Color.green,Color.blue);
//可以给枚举中的值赋予编号
console.log(Color[3]);
console.log('any类型========');
let str8:any = 1000;
str8 = '黎明';
//优点:
let arr4:any[]=[100,'xiao',true,100.2];
//缺点:不会出现错误,编译可通过,但是结果错误
// console.log(arr4[0].split(''))
console.log('void=====没有任何类型')
function showMsg():void{
console.log('xiaoming')
}
showMsg();//xiaoming
console.log(showMsg())//没有返回值 undefined
console.log('Object类型=======')
// 定义一个函数,参数是Object类型,返回值也是Object类型
function getObj(obj:Object):Object{
console.log(obj);
return{
name:'小明',
age:13
}
}
console.log(getObj({name:'12312'}));
console.log('联合类型==========')
function getStr(str:string|number):string{
return str.toString();
}
getStr('123');//'123'
getStr(123);//'123'
console.log('类型断言=======');
// 需求1:定义一个函数获取函数或者字符的长度
function getLength(obj:string|number):number{
if((<string>str).length){
// return str.length;
return (str as string).length
}else{
return str.toString().length;
}
}
console.log('类型推断======')
let numb = 100;
let name;
7、接口
// id是number类型, 必须有, 只读的
// name是string类型, 必须有
// age是number类型, 必须有
// sex是string类型, 可以没有
//定义一个接口,该接口作为person对象的类型使用,限定或者是约束该对象中的属性数据
interface Iperson{
//定义id为只读类型 readonly 不可改变
readonly id:number
name:string
age:number
//sex可有可无 用?
sex?:string
}
//定义一个对象。该对象的类型就是我定义的Iperson
const person:Iperson={
id:1,
name:'gtt',
age:13,
//需求中sex属性可有可无
sex:'女'
}
8、函数类型
console.log('函数类型')
// 函数类型:通过接口的方式作为函数的类型来使用
// 为了使用接口表示函数类型,我们需要给接口定义一个调用签名。
// 它就像是一个只有参数列表和返回值类型的函数定义。
// 参数列表里的每个参数都需要名字和类型
// 函数类型:通过接口的方式,作为函数的类型来使用
// 定义一个接口,用来作为某个函数的类型使用
// 需求:在第一个参数中找第二个参数是否存在其中,返回布尔类型
interface Isearch{
// 定义一个调用签名
(source:string,subStr:string):boolean
}
let searchStr:Isearch = function (source:string,subStr:string):boolean{
return source.search(subStr)>-1
}
console.log(searchStr('haha,小明','明'));//true
9、类类型(类的类型通过接口来实现)
console.log('类');
// 1、定义一个接口
interface IFly{
// 该方法中没有任何的实现(方法中什么都没有)
fly()
}
// 2、定义一个类,这个类的类型就是上面定义的接口(实际上也可以理解为IFly接口约束了当前的这个Person类)
class Person implements IFly{
// 实现接口中的方法
fly() {
console.log('会飞')
}
}
let person1 = new Person();
person1.fly();//会飞
// 3、定义另一个接口
interface ISwim{
swim()
}
// 定义一个类这个类的类型就是IFly,ISwim
//当前这个类可以实现多个接口,一个类可以被多个接口约束
//通俗理解为 一个人可以拥有多个能力
class Person2 implements IFly,ISwim{
fly(){
console.log('fly2')
}
swim() {
console.log('游泳2')
}
}
let person2 = new Person2();
person2.fly();//fly2
person2.swim();//游泳2
//为了避免接口数量过多 我们可以使用接口继承接口
interface FlyandSwim extends IFly,ISwim{};
class Person3 implements FlyandSwim{
fly(){
console.log('fly3')
}
swim() {
console.log('游泳3')
}
}
let person3 = new Person3;
person3.fly();
person3.swim();
// 总结:接口与接口时间叫做继承(extends),类与接口之间叫做实现(implements)
console.log('类2')
// 类:可以理解为模板,通过模板可以实例化对象
// 面向对象的编程思想
class Person{
//定义属性
name:string
age:number
gender:string
// 定义构造函数,为了将来实例化对象的时候,可以直接对属性的值进行初始化
constructor(name:string='gtt',age:number = 13,gender:string='女'){
//更新对象中的属性数据
this.name = name
this.age = age
this.gender = gender
}
// 定义实例方法
sayHi(str:string){
console.log(`大家好,我是${this.name},今年${this.age}岁了,是个${this.gender}孩`,str)
}
}
const person = new Person();
person.sayHi('自我介绍');//大家好,我是gtt,今年13岁了,是个女孩 自我介绍
const person1 = new Person('小明',12,'男');
person1.sayHi('自我介绍');//大家好,我是小明,今年12岁了,是个男孩 自我介绍
11、继承
console.log('继承')
// 继承:类与类之间的关系
// 继承后 类与类 之间的叫法:
// 如:A类继承了B类,那么此时A类叫做子类,B类叫做基类
// 子类---派生类
// 基类---超类(父类)
// 一旦发生了继承关系,就出现了父子类的关系(叫法)
// 1、定义一个类作为基类(超类/父类)
class Person{
// 定义属性
name:string
age:number
gender:string
// 定义构造函数
constructor(name:string,age:number,gender:string){
//更新属性数据
this.name = name;
this.age = age;
this.gender = gender;
}
// 定义实例方法
sayHi(str:string){
console.log(`我是${this.name},今年${this.age},我是${this.gender}孩子`,str);
}
}
//2、定义一个类继承自Person
class Student extends Person{
constructor(name:string,age:number,gender:string){
// 调用父类中的构造函数,使用super
super(name,age,gender)
}
// 可以调用父类中的方法
sayHi(str: string) {
console.log('我是父类中的sayHi方法')
super.sayHi(str);
}
}
// 1、实例化Person
// 2、实例化Student
const person = new Person('小明',13,'男');
person.sayHi('haha');//我是小明,今年13,我是男孩子 haha
const stu = new Student('小倪v',12,'女');
stu.sayHi('嘻嘻')//我是小倪v,今年12,我是女孩子 嘻嘻
12、多态
console.log('多态');
// 多态:父类型的引用只想子类型的对象,不同类型的对象针对相同的方法,产生了不同的行为
// 1、定义一个父类
class Animal{
// 定义一个属性
name:string
// 定义一个构造函数
constructor(name:string){
// 更新属性值
this.name = name
}
// 实例方法
run(distance:number=0){
console.log(`跑了${distance}米`,this.name)
}
}
// 2、定义一个子类
class Dog extends Animal{
// 构造函数
constructor(name:string){
// 调用父类的构造函数,实现子类中属性的初始化操作
super(name)
}
// 实例方法 重写父类中的实例方法
run(distance:number=5){
console.log(`跑了${distance}米`,this.name)
}
}
// 3、再定义一个子类
class Pig extends Animal{
constructor(name:string){
super(name)
}
// 实例方法 重写父类中的实例方法
run(distance:number=10){
console.log(`跑了${distance}米`,this.name)
}
}
console.log('========1')
// 实例化父类对象
const ani:Animal=new Animal('动物');
ani.run(2)
// 实例化子类对象
const dog:Dog = new Dog('小狗')
dog.run();
// 实例化子类对象
const pig:Pig = new Pig('小狗')
pig.run();
//父类和子类的关系:父子关系,此时,父类类型创建子类的对象
console.log('========2')
const pig1:Animal = new Pig('猪猪');
pig1.run();
const dog1:Animal = new Dog('狗狗')
dog1.run();
console.log('=========3')
// 不同类型的对象针对相同的方法,产生了不同的行为 叫多态 有什么用处?
// 调用的是子类中自己的方法
// 定义一个函数需要的参数是Animal类型的
function showMsg(ani:Animal){
ani.run()
}
showMsg(dog1);
showMsg(pig1)
13、修饰符:公共、私有与受保护的修饰符
// 修饰符(类中成员的修饰符):主要描述类中的成员(属性,构造函数,方法)的可访问性
// 类中的成员有自己默认的修饰符 public
// public 类中成员的默认修饰符,代表的是公共的,任何位置都可以访问类中的成员
// private修饰符 类中成员如果使用private来修饰,那么外部是无法访问这个成员数据的,当然子类中也是无法访问该成员数据的
// protected修饰符 类中成员如果用protected来修饰,那么外部是无法访问这个成员数据的,当然,子类中是可以访问该成员数据的
(()=>{
class Person{
// 定义属性
public name:string
// private name:sring
protected age:number
// 构造函数
// new Person的时候实际上就是在调用构造函数
constructor(name:string){
this.name = name
}
// 实例方法
eat(){
console.log('真好吃',this.name)
}
}
const per1 = new Person('大骨头');
console.log(per1.name);//'大骨头';
per1.eat();
})()
13.1 readonly修饰符
- readonly修饰类中的属性值
// readonly修饰符:是一个关键字,对类中的属性成员进行修饰,修饰后该属性成员就不能再外部被随意的修改了
// 构造函数中,可以对只读 属性的成员进行数据修饰
// 如果构造函数中没有任何参数,类中的属性成员已经用readonly进行修饰,那么外部也是不能对这个属性值进行修改的
(()=>{
class Person{
readonly name:string
constructor(name:string) {
this.name = name
}
play(){
// 类中的普通方法中也不能修改readonly修饰的成员属性值
console.log('撕吧新歌',this.name);
}
}
// 实例化对象
const per:Person = new Person('小甜甜')
console.log(per)
console.log(per.name)
console.log(per.play())
// per.name ='大婷婷' 当时用readonly时此处报错,就不能被修改了
console.log(per.name)
- 修饰构造函数中的参数属性
//修饰构造函数中的参数属性
class Person{
// 构造函数
// 构造函数中的name参数,一旦使用readonly进行修饰后,那么name属性就可以教参数属性
// 那么Person中就有了一个name的属性成员
// 外部也是无法修改类中的name属性成员值得
constructor(readonly name:string) {
this.name = name
}
// public修饰后那么Person类中就有了一个公共的name属性成员了
// constructor(public name:string) {
// this.name = name
// }
// private修饰后那么Person类中就有了一个私有的name属性成员了
// constructor(private name:string) {
// this.name = name
// }
// protected修饰后那么Person类中就有了一个受保护的name属性成员了只能在本类和派生类中保护和使用了
// constructor(protected name:string) {
// this.name = name
// }
play(){
// 类中的普通方法中也不能修改readonly修饰的成员属性值
console.log('撕吧新歌',this.name);
}
}
// 实例化对象
const per:Person = new Person('小甜甜')
console.log(per)
console.log(per.name)
console.log(per.name)
13.2存取器
// 存取器:让我们可以有效的控制对象中成员的存取操作,通过getters和setters来进行操作
// 外部传入的数据可以通过set get进行控制,外部也可以进行修改
class Person{
firstName:string
lastName:string
constructor( firstName:string,lastName:string){
this.firstName = firstName
this.lastName = lastName
}
// 读取器-----负责读取数据的
get fullName(){
console.log('get---------')
return this.firstName+'_'+this.lastName;
}
// 设置器-----负责设置数据的(修改)
// 获取到名字重新赋值给firstName和lastName
set fullName(val){
console.log('set-------')
let names = val.split('_');
this.firstName = names[0];
this.lastName = names[1];
}
}
// 实例化对象
const name1:Person = new Person('东方','不败');
console.log(name1.fullName);
// 设置该属性的数据
name1.fullName = '诸葛_孔明';
console.log(name1.fullName);
13.3静态成员
// 静态成员:在类中通过static修饰的属性或方法,就是静态的属性以及方法,也称之为:静态成员
// 静态成员调用的时候通过类名.的方式来调用
class Person{
static name1:string='小'
// 构造函数不能通过static来进行修饰
constructor(name:string){
// 此时this是实例对象,name1是静态属性,不能通过实例对象直接调用静态方法来使用
// this.name1 = name
}
// 静态方法
static sayHi(){
console.log('nihao')
}
}
// let per:Person = new Person('小雨');
// 通过实例调用的属性(实例属性)
// console.log(per.name1)
// 通过实例调用的方法(实例方法)
// per.sayHi()
// 通过类名.的形式直接访问 可以不用实例化对象了
console.log(Person.name1)
Person.sayHi();
// 也可以直接设置该成员属性数据
Person.name1 ='佐助'
console.log(Person.name1)
13.3抽象类
// 定义一个抽象类
// 抽象类:包含抽象方法(抽象方法一般没有任何的具体内容的实现),也可以包含实例方法
// 抽象类是不能被实例化的,为了让子类进行实例化以及实现内部的抽象方法
// 抽象类的目的或作用最终都是为子类服务
(()=>{
abstract class Animal{
// 抽象属性
abstract name:string
// 抽象方法
// 报错:抽象方法不能有具体的实现
// abstract eat(){
// console.log('跳着吃')
// }
abstract eat()
// 不同动物有不同的吃的方式(狗、鸟)因此需要抽象化 在具体的子类中实现
// 实例方法
sayHi(){
console.log('你好啊',this.name)
}
}
// 报错: 不能实例化抽象类
// const ani:Animal = new Animal('黄')
class Dog extends Animal{
name:string='小黄'
// 重新实现抽象类中的方法,此时这个方法就是当前Dog了的实例方法了
eat(){
console.log('舔着吃,真好吃')
}
}
const dog:Dog = new Dog()
dog.eat();
dog.sayHi()
})()
14、函数
(()=>{
console.log('函数')
// js中的函数的写法
// 1、函数声明,命名函数
// function add(x,y){
// return x+y
// }
// 2、函数表达式,匿名函数
// const add2 = function(x,y){
// return x+y
// }
// ts中的写法 函数中的参数一般会指定类型
// 1、函数声明,命名函数
function add(x:string,y:string):string{
return x+y
}
const res1:string = add('111','222')
console.log(res1)
// 2、函数表达式,匿名函数
const add2 = function(x:number,y:number):number{
return x+y
}
const res2:number = add2(111,222)
console.log(res2);
// 函数的完整写法
// add3======》变量名-----函数add3
// (x:number,y:number)=>number当前的这个函数的类型
// function(x:number,y:number):number{return x+y} 相当于符合上面这个函数的类型
const add3:(x:number,y:number)=>number=function(x:number,y:number):number{
return x+y
}
})()
14.1函数可选参数
(()=>{
// 可选参数:函数声明时,内部的参数用?号进行修饰,就表示该参数可传可不传
// 默认参数:函数在声明的时候,内部参数有自己的默认值
// 定义一个函数 当姓 名都有得到姓名,否则得到姓氏
const getName = function(firstName:string='东方',lastName?:string):string{
if(lastName){
return firstName+'_'+lastName;
}else{
return firstName
}
}
// 无参
console.log(getName());//东方
// 单参
console.log(getName('诸葛'));//诸葛
//双参
console.log(getName('诸葛','孔明'))
})()
14.2剩余参数
(()=>{
// 剩余参数是放在函数声明的所有参数的最后
//...args:string[]-----剩余参数,放在了一个字符串的数字中,args里面
function showMsg(str:string,...args:string[]){
console.log(str);'a'
console.log(args);['b','c','d']
}
showMsg('a',"b","c","d")
})()
14.3函数的重载声明
// 函数重载:函数的名字相同,函数的参数以及个数不同
(()=>{
// 定义一个函数
// 函数重载声明
function add(x:string,y:string):string
function add(x:number,y:number):number
// 需求:有一个add函数,可以接收两个string|number参数进行拼接或相加
function add(x:string|number,y:string|number):string|number{
if(typeof x==='string'&&typeof y==='string'){
return x+y
}else if(typeof x==='number'&& typeof y==='number'){
return x+y
}
}
//函数调用
console.log(add('诸葛','孔明'));
console.log(add(100,200));
// 当参数的形式不符合条件时 这时候就需要我们使用函数重载声明
// 如:add('小明',100) 这时就会报错
// 如上 对函数的参数进行重载声明
})()
15、泛型
(()=>{
console.log('泛型')
// 在定义函数、接口、类的时候不能预见确定要是用的数据类型,而是在使用的时候才能确定
// 需求:定义一个函数,传入两个参数 第一个是数据 第二个是参数的数量
// 函数的作用:根据数量 创建一个对象数量的数据 数组并且返回
// 当全是数字时
function getArr(value:number,count:number):number[]{
const arr:number[]=[]
for(let i=0;i<count;i++){
arr.push(value);
}
return arr
}
// 但是当需求改变 传入的是字符 需要返回字符数组的时候 我们定义的函数就不能使用了
// 这个时候就需要泛型
// 可以使用any类型还注解
// 但是会发现问题 当数字时我们对数字使用.toFixed()方法或者对string使用split方法时并不会提示
// 所以我们使用泛型
function getArr4<T>(value:T,count:number):T[]{
const arr:Array<T>=[]
for(let i=0;i<count;i++){
arr.push(value)
}
return arr
}
const arr1=getArr4(200.123,4);
const arr2 = getArr4('abc',6)
console.log(arr1[0].toFixed(2));//会有提示 说明arr1[0]为number类型 同理string split()方法
})()
15.1多个泛型参数的函数
(()=>{
// 泛型字母通常可以说使用大写字母 T、K、V
function getMsg<K,V>(value:K,value2:V):[K,V]{
return [value,value2]
}
const arr1 = getMsg<string,number>('jack',123.12)
console.log(arr1[0].split(''))
console.log(arr1[1].toFixed(1))
})
15.3 泛型 接口
在这里插入代码片