typescript学习

54 阅读8分钟

Typescript

一:简介

TypeScirpt是JavaScript的超集,为Javascript的生态增加了类型机制,并最终将代码编译为纯粹的Javascript代码。

  1. 全局安装typeScript

     npm install -g typescript
    

    在项目中执行以下命令,表示项目初始化,会生成tsconfig.json文件

     tsc -init
    
  2. 在项目中新建test.ts

     let name = "张三";//根据初始化的赋值,可以推导出变量的类型。以后这个变量的类型是不可修改的。
     //name = 1;//类型不一致,报错。
     const userName = '张三';//常量不可以修改,所以它的值就是它的类型
    

3.执行命令:tsc 文件名,编译ts文件,编译后会生成一个js文件。也可以通过如下图的方式,此方式生成js文件并实时监听

    tsc test.ts
    
    tsc -p tsconfig.json --watch //如果下图功能

image.png

二:变量类型

  1. 原始类型 ts的原始类型就是js的基础数据类型:string,number,boolean,null, undefined,symbol

     let str:string = "11";
     let num:number = 1;
     let bol:boolean = true;
     let nul:null = null;
     let und:undefined = undefined;
     let sy:symbol = Symbol('123');//Symbol('123')!= Symbol('123');symbol是每次都是新的内存空间
    

    //在函数中如果没有返回值,函数类型就是void function a():void{}

  2. 非原始类型:object Object {};其中Object等同于{}

     //object 不包含基础数据类型
     let obj:object = {a:1};
     let arr:object = [1,2];
    
     //Object 包含基础数据类型
     let obj1:Object = {a:1};
     let arr1:Object = [1,2];
     let str1:Object = '123';
     let num1:Object = 1;
     let bol1:Object = true;
    
  3. 数组类型

     let arr1:number[]=[1,2,3];
    
     //泛型,类型参数化
     let arr2:Array<number>=[1,2,3];
    
     //元组,位置定死
     let arr3:[number, number, string, boolean] = [1,2,'3',true];
    
  4. 联合类型'|'

     let str:number|string=1;
     str='1';
    
     let num:1|'2'=1;
     num = "2";
    
     let obj:{a:1}|{b:'2'} = {a:1};
     obj = {b:'2'};
     obj = {a:1,b:'2'};
     
     let obj1:{a:number}|{b:string} = {a:3};//表示有a属性或者有b属性,或者都有
     obj1 = {b:'张三'};
     obj1 = {a:2,b:'李四'};
    
     let arr:(number|string)[] = [1,'2','1'];
    
  5. 交叉类型'&'

     let obj:{a:number}&{b:string,c:number} = {a:3,b:'1',c:1};//abc三个属性都必须有
    
  6. any与unknown的区别

     //不推荐使用any,any绕过了类型校验
     let a:any = 1;
     a = '1';
     a = [1,2];
     a = {c:1};
     a.toFixed(2);//不报错,绕过了校验
    
     let b:unknown = 1;
     b = '1';
     b = [1,2];
     b = {c:1};
     b.toFixed(2);//报错,有做类型校验
    
  7. 接口类型interface,用来自定义类型

     //定义接口类型--给对象用
     interface Person{
         //属性名:值的类型
         name:string,
         age:number,
         address:string
     }
    
     //接口定义的属性都必须有
     let obj:Person = {
         name:'张三',
         age:19,
         address:'江苏'
     };
    
    
     //定义接口类型--给数组用
     interface ArrInter{
         //[idx:number]下标类型:值的类型
         [idx:number]:number|string
     }
    
     let arr:ArrInter = [1,2, '3'];
    
    
     //定义接口类型--给函数用
     interface FunInter{
         //形参及参数:值的类型
         (num:number):void
     }
    
     let fun:FunInter = (num:number)=>{}
    

8.接口继承extends

//定义接口类型
interface Person{
    //属性名:值的类型
    name:string,
    age:number,
    address:string
    //[idx:string]:number|string
}

interface Hobby{
    hobboyName:string,
    hobboyLevel:number
}

//接口继承,具有父接口的所有属性
interface User extends Person,Hobby{
    enLevel:number;
}

//属性都要有
let obj:User = {
    enLevel:2,
    name:'张三',
    age:18,
    address:'112',
    hobboyLevel:12,
    hobboyName:'12'
}

9.接口同名

//接口可以同名,相当于属性合并
interface Person{
    //属性名:值的类型
    name:string,
}

interface Person{
    age:number,
    address:string
}


let obj:Person = {
    name:'张三',
    age:18,
    address:'112',
}

10.接口缺省?,只读readonly

interface Person{
    readonly name:string,//readonly表示这个属性只读,不可以修改
    age?:number,//?表示这个属性可以缺省,定义属性的时候可以不写
    address:string
}


let obj:Person = {
    name:'颤三',
    // age:18,
    address:'112',
}

obj.name="lisi";//报错,因为是只读属性

11.联合交叉类型

let obj:{a:string}&{b:number}|{a:number}&{ b:string}={
    a:'aa',
    b:1
};

obj = {
    a:11,
    b:'11',
}


let obj1:{a:string}&{b:number}&{h:number}|{a:number}&{b:string}&{ c:string}&{d:number}={
    a:'aa',
    b:1,
    h:11
};

obj1 = {
    a:112,
    b:'1',
    c:'dd',
    d:1,
    h:12
}

12.类型别名Type 与interface的区别是,都可以自定义类型,但是Type不能重复定义,接口可以

type BasicType = string|number;
let a:BasicType = '1';
a = 1;

//定义给对象
type ObjType = {a:string, b:number};
let obj:ObjType = {
    a:'aa',
    b:1
}

//定义给函数
type funType = (a:number)=>void;
let fun:funType = (a:number)=>{};

interface Person{
    name:BasicType,
    age:number
}

let user:Person={
    name:'11',
    age:10
}

user.name = 11;

//用类型别名保存接口上某个属性的值类型
type Itype = Person['age'];
let testType:Itype = 11;

13.函数

//剩余参数(...)
function fun1(a:number, b:number,...arr:number[]):number{
    return a+b
}

//缺省参数(?)
function fun2(a:number, b?:number):number{
    return a
}

//默认参数(=)
function fun3(a:number, b:number=1):number{
    return a+b
}

 function fun(a:number, b:number):number{
    return a+b
}

//定义接口类型
interface Calc{
    (a:number, b:number):number;
}

let funCalc:Calc = (a:number, b:number)=>{
    return a+b;
}


//定义给函数
type funType = (a:number, b:number)=>number;
let fun1:funType = (a:number, b:number)=>{return a+b};



//////函数作为对象的属性
//接口定义
interface ObjInt{
    fun:Calc
}

let obj:ObjInt = {
    fun:(a:number, b:number) => {
        return a+1
    }
}
obj.fun(1,2);

//类型别名
type objType = {fun:funType}

let obj2:objType = {
    fun:(a:number, b:number) => {
        return b+2
    }
}

obj2.fun(1,2);

14.Promise

//定义类型 
interface PromiseInter{
    data:string,
    code:number,
    msg:string
 }

let fun:Promise<PromiseInter> = new Promise((resolve,reject) => {
    resolve({
        data:'',
        code:0,
        msg:''
    })
})

fun.then(res => {
    console.log(res.data)
})

15.this的使用 window就是Window这个类型的对象

/////在全局上,给Window接口扩展属性
//接口可以同名
interface Window{
    title:string;
}

function Person(this:Window, name:string){
    //在ts中,需要指明this的指向,在函数的第一个形参中注明。Window中没有title属性,需要自己扩展
    this.title = name;
}

window.Person('tt');

//this非window指向
interface ObjInt{
    title:string,
    Person:(n:string)=> void
}

let obj:ObjInt = {
    title:'标题',
    Person:(name:string)=> {}
}
function Person(this:ObjInt, name:string){
    //在ts中,需要指明this的指向,在函数的第一个形参中注明。Window中没有title属性,需要自己扩展
    this.title = this.title+name;
}

obj.Person = Person;
obj.Person('tt');

16.枚举,用来列举数据用的。

enum StatusCode{
    success=200,
    error=500
}

let code:number = 200;
if(code == StatusCode.success){
    console.log('成功')
}else if(code == StatusCode.error){
    console.log('失败')
}else{
    console.log('其他')
}

enum StatusCode1{
    success,//0
    error=500,
    fail//501
}

17.泛型,泛型约束extends

//泛型-类型的形参,T是一个标识符,可以自定义,T表示某种类型。类型参数化
function fun<T>(n:T):T{
    return n
}

function fun1<A>(n:A):A{
    return n
}

fun<number>(1);
fun1<number>(2);
fun1<boolean>(false);


function fun2<A,B>(n:A,m:B):A{
    return n
}

fun2<number, string>(1,'2')

//--------泛型在类型别名和接口上的应用
type StrOrNum = string|number;

interface Person<T,C,A,G>{
    name:T;
    age:A,
    getName:(name:C)=>G;
}
let obj:Person<string, string, StrOrNum,void> = {
    name:'zhanshan',
    age:'2',
    getName:()=>{}
}

function getNa(this:Person<string, string, StrOrNum, void>, name:string) {
    this.name = name;
}

obj.getName = getNa;

//--------可以设置默认类型
interface Person1<T=string,C,A,G>{
    name:T;
    age:A,
    getName:(name:C)=>G;
}

//--------约束,T只能是string或者number类型
interface Person2<T extends StrOrNum,C,A,G>{
    name:T;
    age:A,
    getName:(name:C)=>G;
}

18.类

//定义类的同时,生成一个相同名称的接口
class Person{
    //定义属性
    myName:string;
    //默认值
    myAge:number = 1;

    constructor(n:string){
        this.myName = n;
    }

    getAge(){
        return this.myAge;
    }
}

let person = new Person('张三');
console.log(person.myName);
console.log(person.getAge())

//相当于接口
// interface PersonInt{
//    //定义属性
//    myName:string;
//    //默认值
//    myAge:number;

//    getAge:() => number;
// }


let obj:Person={
    myName:'11',
    myAge:10,
    getAge:()=>{
        return 333
    }
}

//--------类的继承
class Stu extends Person{
    snum:string;

    constructor(name:string, num:string){
        super(name);//调用回父类的constructor,并把参数传进去

        this.snum =num;
    }

    getAge(){//与父类方法名相同,重写
        return 100
    }
}

let stu = new Stu('aa','11');

//--------类的修饰符
//类中定义的属性,默认修饰符就是public,public修饰的属性和方法在类的内部、类的外部和子类也可以访问
//protected受保护,在类的内部和子类中都可以访问,类的外部不可以访问
//private私有,在类的内部可以访问,子类和类的外部不可访问
class Dog{
    public name:string;
    //readonly 设置属性只读
    // public readonly name:string;
    protected age:number=10;
    private type:string ='泰迪';

    constructor(n:string){
        this.name = n;
    }

    public getName(){
        return this.name;
    }
}

class Anima extends Dog{
    //静态属性static
    static title:string = "测试";//静态属性/成员,是给类用的
    
    constructor(n:string){
        super(n);
    }

    getAge(){//可以访问
        return this.age
    }

    // getType(){//报错,不可以访问
    //     return this.type
    // }
}

let anima = new Anima('111');
// console.log(anima.age);//报错,不能访问
// console.log(anima.type);//报错,不能访问

Anima.title = '111'

19.抽象类和接口

//抽象类是普通类的描述,指定类的规范,给类继承。继承之后,普通类里面就必须定义抽象类里面的抽象方法和属性
//抽象类中的普通方法直接继承,在普通类中可以不用实现
abstract class Person{
    //抽象属性
    abstract myName:string;
    //抽象方法
    abstract getName():string;

    getAge(){
        return '11'
    }
}

class Student extends Person{
    myName:string = '张三';
    getName(){
        return 'test'
    };
}

let student = new Student();
console.log(student.getName());
console.log(student.getAge());

//抽象类不能被实例化
// let tea = new Person();//报错

//定义接口给类用
interface PersonInter{
    myName:string;
    getName:() => string;
}

class Teacher implements PersonInter{
    myName:string = "";
    getName() {
        return 'abc'
    }
}

20.keyof,in,typeof

//定义接口给类用
interface PersonInter{
    myName:string;
    age:number;
    [idx:number]:string|number;//[idx:string]:string|number;
}

//keyof
type typePerson = keyof PersonInter;//'myName' | 'age'|number

let type:typePerson = 'myName';
type = 1;

//in
type StrOrNumber = string|number;
type TypeObj = {
    [k in StrOrNumber]:string
}

let obj:TypeObj = {
    1:'11',
    name:'ddd'
}

//typeof,提取变量或者对象的类型
let str = '22';
type StrType = typeof str;

let obj1 = {
    name:'1',
    age:10
}

type ObjType = typeof obj1;
let obj2:ObjType = {
    name:'test',
    age:100
}

21.extends和类型推断infer

//extends
type FuType<P> = P extends string|number?P[]:P;

let num:FuType<number> = [1,2];
let bln:FuType<boolean> = false;

//infer类型推断
type ObjType<T> = T extends {a:infer A, b:infer B}?[A,B]:null;
let obj:ObjType<string> = null;
let obj1:ObjType<{a:string, b:number}> = ['1',1];