typescript基础进阶(学习笔记一)

61 阅读10分钟

一、typescript基础

1.typescript环境搭建

  • 自动监听单个ts文件变化tsc one.ts -w
  • 监听所有ts文件变化tsc --init 会生成一个tsconfig.js文件

执行tsc 转成es6
执行tsc -w 监听所有ts文件变化

    • 让生成的编译成js的文件放在一个叫js文件夹下面

在tsconfig文件下找到outDir配置成“./js”

  • 以上还有一种方法,使用编辑器的插件(vscode、webstorm...)
  • npm i -g tsc-node 测试环境下直接运行ts文件

2.配置tsconfig.js

image.png

image.png

image.png

3.typescript类型声明基本语法

let str:string = 'hi'

声明参数类型
function add(num1:number,num2:number){}
声明返回值类型
function add(num1:number,num2:number):number{
    return 返回数字类型
}

4.ts的基本类型

  • number
  • boolear
  • string
  • 数组
    声明字符串数组:let arr:string[]=[] *
    通过泛型声明字符串数组:let arr:Array<string> = []
  • 对象

5.ts特殊类型

  • null let a:null = null 值只有null
  • undefined 同上
  • any:任意类型相当于关闭ts,不建议使用
  • unknow:表示未知类型,一个类型安全的any,不能赋值给其他变量

可以赋值给unknow或ant
如果要赋值给其他类型如下图

image.png

  • void:表示空,一般用于函数有无返回值
  • never:表示永远不会有返回值

6.typescript中对象和函数的类型声明

  • object
    1.对象类型声明,数据可有可无写法

    image.png
    2.对象类型声明,有个别数据不是必有向 变量后面加文号?
    let obj:{name:string,age:number,sex?:string}

  • function 1.基本函数
    声明: function fn(a:number,b:number,c?:number):number{} 调用:fn(1,2)
    2.箭头函数

                声明: const fn:(a:number,b:number) => number
                        fn=(n1,n2) => n1+n2  
                        ------------------------------------
                        const fn:(a:number,b:number) => number = function(n1,n2):number{retunr n1+n2}
                        --------------------------------------------------------
                        const fn:(a:number,b:number) => number = (n1,n2) => n1+n2
                调用:fn(1,2)
    

    3.匿名函数

image.png

7.typescript中的一些运算符号的应用

  • 联合类型
    1. | 相当于 || let info:string|number 类型可以是字符串可以是数字
      let arr(number | string | boolear)[] = [1,'str']
    2. & 必须同时满足
      let obj:(name:string) & (age:number)
      obj = {name:"jack",age:18}
      3.字面量进行类型声明
      let num:10 值只能是10 相当于是常量 let sex:"男" | "女" 值只能是男或者女

8.typescript中的一些关键字

  • 元祖(tuple):固定数组的长度和类型
    let arr:[string,number]=["str",1]

    二维元祖定义
    let arr:[string,number][]=[    ["jack",10],
        ["rows".20]
    ]  
    
  • 枚举(enum):限制在值得范围内使用枚举比较方便
    let state:1 | 2| 3 | 4 这样的使用枚举比较方便

    enum state{
        famal:0,
        male :1
    }
    //值会自动往下加1,不指定值默认从0,只读
    //调用
    console.log(state.famal)
    
  • 类型的别名

    type mystate = 1|2|3|4|5
    let state:mystate
    // state = 1
    state = 8 //报错
    
    //函数别名
    type myvar = string | number | blooean
    function(a:myvar,b:myvar,c:myvar){
    }
    
    //定义
    type myfun = (a:number,b:number) => number
    //使用
    let fun:myfun = (a,b) => a * b
    //调用
    fun(10,20)
    
    //对象别名
    type myobj = {name:string,age:number}
    let person:myobj={name:'jack',age:10}
    

    类型断言(强制类型转换)

  • 类型缩小

    function demo (n:number|string){
        console.log(n.lenght) //会出现报错 number没有length属性
        let len:number
        if(typeof n == "string"){
            len = n.lenght
        }
        console.log(len)
    }
    
  • 类型断言

    function demo (n:number|string){
        console.log(n.lenght) //会出现报错 number没有length属性
        let len:number
        //第一种
        len = (<string>:n).length
        //第二种
        len = (n as string).length
        console.log(len)
    }
    
  • as const 应用:相当于转换成字面值变量而不是常量,根据具体的值转换

    //常量和字面量值的区别
    //常量不能复制,字面量值可以赋值但是只能是哪一个值
    const abc = "abc"
    abc = "abc"//报错
    //字面量
    let abc:"abc"="abc"
    abc="abc"
    //数组
    let arr1 = ["www",12] as const //变成只读的元祖
    let arr2 = <const>["www",12] //同上 建议使用上面那种
    //对象
    let user = {
        name :“Jack”,
        age :18
    }as const //变成只读的obj
    
    //在解构中使用as const
    function ew (){
        let str = "www.baidu"
        let fun = (a:number,b:number):number => a+b
        return [str,fun]
    }
    //let [nstr,nfun] = ew()
    //直接调用 nfun(1,2)会报错 有可能是字符串
    //第一种
    let [nstr,nfun] = ew() as [string,function]
    //第二种
    let [nstr,nfun] = ew()
    //nfun as  Function(1,2)
    nfun as  ((a:number,b:number) => number)(1,2)
    //第三种
      function ew (){
        let str = "www.baidu"
        let fun = (a:number,b:number):number => a+b
       // return [str,fun] as [string,function]
       //return [str,fun] as [typeof str,typeof fun]
       return [str,fun] as const //推荐
    }
    
  • 非空断言 !dom断言

    image.png

二、typescript进阶

1.函数式编程

  • 函数类型
//(n,number,m:number) => number 这不是箭头函数 这是声明函数参数类型,和返回值类型
//声明函数类型
type myfun = (n:number,m:number) => number
//let myfun = function(a,b){}
let fun:(n,number,m:number) => number = function(a,b){
    retunr a+b
}
let fun2:myfun = (a,b) => a+b
  • 参数为回调函数
type myfun = (n:number,m:number) => number
function calc(a:number,b:number,fn:myfun){
    return fn(a,b)
}
let result:number = calc(10,20,(a,b) => a + b)
console.log(result)
let result2:number = calc(10,20,function(a,b){return a * b})
console.log(result2)
  • 函数参数灵活用法
//参数的可选类型  ? === undefined 可以传undefined 第一个不能是可选
type myfun = (n:number,m?:number) => number
const fun:myfun = function(a,b){
    retunr 10
}
fun(1)
//参数的默认值
const fun = function(a:number = 1,b:number=2){
    console.log(a,b)
}
fun()
//函数剩余参数
    //扩展运算符
    function fn(..args:any[]){
    //function fn(..args:number[]){ 限制number类型就只能传number
    //function fn(a:number,b:number,...args:number[]){
       // console.log(args) // [1,2,str]
        console.log(a) //1
        console.log(b) //2
        //console.log(args) [3,str]
    }
    fn(1,2,"str")
    fn(1,2,3,"str")
    //
  • 函数重载(ts新加的功能,es6,script没有)
//解决方法名相同,参数类型,参数个数,参数顺序不同,函数返回值不确定 === 重载
//声明
let add(a:number,b:number):number
let add(a:string,b:string):string
//实现
function add(a:any,b:any):any{
    return a + b
}
//调用
add(1,2)
add("www","com")

2.面向对象编程思想

对象的思想、语法: 类,接口...声明
三大特性:封装,继承,多态

3.类(es6中类的用法+ts增强)

  • 类的概念

image.png

  • 类的声明
class Person{
    name : string;
    age:number;
    //初始化值。创建的时候给值
    constructor(name:string,age:number = 0){
        this.name = name;
        this.age = age;
    }
    say(){
        console.log(this.name +"说话")
    }
}
const p1 = new Person()
pq.say()
  • 类的继承(扩展):代码的可复用性
class Person{
    name:string;
    age:number;
    constructor(name:string,age:number = 0){
        this.name = name;
        this.age = age;
    }
    say(){
        console.log(this.name +"说话")
    }
}

class Student extents Person{
    school:string;
    constructor(name:string,age:number,school:string){
        super(name,age);
        this.school = school;
    }
    stydy(){
        console.log("在" + this.scool + "学习")
    }
}
const s1 = new Student("jack",18"元时代");
s1.say()
s1.study()

class Teacher extents Person{
    price:number;
    constructor(name:string,age:number,school:string,price:number){
        super(name,age,school);
        this.price = price;
    }
}
const t1 = new Student("jack",18"元时代",2200);
s1.say()
s1.study()
console.log(s1.price)
//方法的重写 == 方法名相同 会覆盖父类的方法
//方法的扩展 
class Teacher extents Person{
    price:number;
    constructor(name:string,age:number,school:string,price:number){
        super(name,age,school);
        this.price = price;
    }
    stydy(){
        super.stydy()
       console.log("在" + this.scool + "备课")
    }
}
const t1 = new Teacher("jack",18"元时代",2200);
t1.study() // 在元时代学习  在元时代备课
  • 类成员的访问修饰符(封装)
//public:默认的、缺省的,类的内部、类的外部、子类中都可访问
//private:私有的,只能在类的内部
//protected:受保护的,只能在类的内部和子类内部使用
//readonly:只读的,类内部、类外部都可访问 == const

class Person{
    //public name:string;
    name:string;
    age:number;
    //public constructor(name:string,age:number = 0){
    constructor(name:string,age:number = 0){
        this.name = name;
        this.age = age;
    }
    //public say(){
    say(){
        console.log(this.name +"说话")
    }
}
  • 封装(ts提供了存取器)
//封装类的方法
class Person{
    name:string;
    constructor(name:string){
        this.name = name;
    }
   run(){
       this.left()
       this.right()
   }
   private left(){
       console.log("迈左腿")
   }
   private right(){
       console.log("迈右腿")
   }
}
//封装类的属性
class Person{
    name:string;
    private _age : number;
    constructor(name:string,age:number){
        this._age = name;
    }
    //ts提供的存取器
    set age(age:number){
        this._age = age
    }
    get age(){
        return this._age
    }
    // ==========================
    //两者区别:调用不一样
    setAge(age:number){
        this._age = age
    }
    getAge(){
        return this._age
    }
}

const p1 = new Person("jack",20);
//ts提供的存取器
console.log(p1.age)
//普通方法
console.log(p1.getAge())

  • 静态static的应用

静态成员不在对象中,在类中存在,通过类名调用
在静态方法里面只能访问静态成员 this.静态成员
在静态方法里面this代表类
在非静态方法里面访问静态成员不能使用this需要使用类名.静态成员
static的目的:想让一个类的内部成员,让所有对象,以及类的内部外部直接用类名访问就声明成静态成员,静态方法

class Person{
    static name:string = "";
    age:number=18;
    static say(){
        console.log(123)
    }
}
const p1 = new Person("jack",18);
p1.name //会报错
Person.name

4.抽象类与接口

  • 抽象类(abstract)
abstract class Person{
    name:string = "jack";
    static say(){
        console.log(this.name)
    }
    abstract run():void //抽象方法:没有方法体的方法就是抽象方法,只要有一个抽象方法这个类就属于抽象类
}
//const p1 = new Person() 报错

class Demo extends Person{
    //重写抽象方法,让子类不是抽象类就可以通过实例化对象进行访问
    run(){
        console.log(11)
    }
}

⑴:抽象类不能够被实例化,意味着抽象类中的不管是不是抽象方法都是不能调用
⑵:抽象类作用:约束子类必须有抽象方法的实现
⑶:抽象类是一个特殊的类,结合多态使用

  • 接口(interface)
interface One{
    //属性只能是共有的
    hello:string;
    //say(name:string):void
    say:(name:string) => viod
    //只写结构让子类去实现
}
//声明接口
interface Two{
    foo():void
}
//接口继承/两种方式
interface Three extends One,Two{
    far():void
}
//抽象类实现接口
abstract class Three extends One{
    
}
//实现接口(implement)
//class Four extends Demo implement Three{
class Four implement Three{
    hello:string = "hello"
    far(){}
    foo(){}
    say(){}
}

⑴:接口又是一个特殊的抽象类
⑵:接口里面不能有普通的成员方法
⑶:成员方法必须是共有的
⑷:接口里面所有的方法都是抽象方法
⑸:接口里面所有的属性和方法都是抽象的可以没有初始值
⑹:一个接口可以继承多个子接口
⑺:可以继承一个类在实现多个接口

  • 多态
//用接口来规范USB
interface USB {
 start():void;
 run():void;
 end():void;
}
//调用接口
function demo(u:USB){
    u.start();
    u.run();
    u.end();
} 
//实现接口
class shubiao implement USB{
    start(){
        console.log("shubiao开始")
    }
    run(){
        console.log("shubiao运行")
    }
    end(){
        console.log("shubiao结束")
    }
}
demo(new shubiao())

//demo({
//    start(){},
 //   run(){},
 //   end(){}
//})

⑴:必须有继承关系
⑵:将子类对象赋给父类的应用,调用父类的方法其实就是在执行子类中具体的方法

  • 面向对象接口的应用
    Ⅰ:声明对象的几种方式
//类类型
class Person{
    name:string = "";
    age:number= 0
}
const p:Person = new Person()
const p1:Person = {
    name:"jack",
    age:10
}
const p2 = new Person()

//
const o1:{
    name:string,
    age : number
}={
    name :"abc",
    age:10
}

//类型别名方式
type myObj = {name:string,age:number}
o2:myObj = {
    name:"edu",
    age:18
}
//接口方式
interface One{
    name:string,
    age:number
}
o3:One={
    name:"abc",
    age:19
}

创建对象接口和类型别名方式的区别
1.接口可以继承
2.接口可以重名,重名自动合并
只要是对象都使用接口方式interface
3.在接口中可以声明只读属性 readonly,可选属性在name ? : string
4.接口中声明任意属性
interface list {[item:number]:string} key是数字类型value是字符串类型的 const l1:list = {1:"one" ...}

5.泛型(类型参数化)

  • 类型参数化:在声明的时候不指定类型,在调用的时候决定

function fun<T>(arg1:T,arg2:T,arg3:T):T{
//function fun<T,W,O>(arg1:T,arg2:W,arg3:O):T{
    return arg2
}
fun<number,string,{name:string}>(1,2,{name:"ab"})
  • 泛型灵活运用
1.泛型参数的默认类型
function fun<T = number>(arg:T){

}
fun<string>("abc")
2.泛型约束
interface ILength{
    length:number
}
function fun<T extends ILength>(arg:T):number{
    return arg.length
}
//fun(10) 报错数字没有length
fun("abc")
fun([1,2,3])
fun({name:"jack",lenght:10})
3.泛型接口
interface IPerson<T1=string,T2=number>{
    name:T1,
    sex:T2
}
cosnt p:IPerson<string,number> = {
    name:"jack",
    sex:10
}
4.泛型类
class Person<T1,T2>{
    name:T1;
    sex:T2
    constructor(name:T1,sex:T2){
        this.name = name
        this.sex = sex
    }
}
//const p1 = new Person("jack",10) 调用自动推断
//const p2 = new Person<string,number>("jack",10)//指定类型 
const p2:IPerson<string,number> = new Person("jack",10)//指定类型 

//回顾数组
1、普通字符串数组
const arr:string[] = ["a","b"]

2.通过泛型声明数组
const arr2::Array<number> = [1,2,3]

三、开发工程化

1.使用webpack打包TS文件(vue、react、vite...)

image.png

2.typescript命名空间(namespace)

namespace One{
   export let str:string; //要想在外面使用就得导出
   console.log(str)
}
console.log(One.str)
namespace Two{
    let str:string;
    console.log(str)
}
console.log(Two.str) //报错没有导出