美文网首页
TypeScript基础

TypeScript基础

作者: 强某某 | 来源:发表于2018-12-01 14:23 被阅读4次

    安装TypeScipt编译器

    npm i typescript -g

    编译指令

    tsc 1.ts --outDir ./dist
    如果不加--outDir则默认会编译到ts同一目录
    ts-node

    tsconfig:


    "./src":只编译src目录下文件,内部子文件夹不编译

    "./src//":代表递归编译文件夹内部所有子文件夹 后面代表所有文件

    ts-node:其他类型编译器 ts-node直接编译


    ts数据类型


    数字,字符串,布尔值

    null underfined

    数组 元组 枚举

    void any Never


    类型系统


    string number boolean 基本类型

    String Number Boolean 对象类型


    基本类型可以赋值给包装类型,但是反之不可

    数组(必须存储同一类型)

    //基本语法
    //数组的声明,此时push是没用的,因为未定义
    // let arr:number[];
    //数组的定义
    let arr:number[]=[];
    //泛型方式
    // let arr1:Array<number>;
    arr.push(...[1,2,4])
    console.log(arr)
    

    元组(类型不必相同)

    let data:[number,string,boolean];
    data=[1,"a",true];
    说明:元组再3.1之后,不能越界使用联合类型了,而且赋值和定义的类型要一一对应
    

    联合类型

    //多个类型中的一个  或的关系
    let a:string|number|boolean=20;
    a="a";
    console.log(a)
    

    交叉类型

    
    //多个类型的叠加,并且的关系
    let b:string&number=
    
    

    枚举

    enum Color{
        RED,
        YELLOW
    }
    console.log(Color.RED);//0
    console.log(Color.YELLOW);//1
    
    enum Color{
        RED=1,
        YELLOW
    }
    console.log(Color.RED);//1
    console.log(Color.YELLOW);//2
    

    Never

    说明:代表那些永远不存在的值的类型,ts也可以自动推断,never此时也可以省略
    function err():never{
        throw new Error("error")
    }
    

    Any

    说明:任意类型,在不确定数据类型的情况下使用
    let a:any="a";
    a=10;
    console.log(a)
    

    函数

    //函数表达式
    let f:()=>string=function():string{
        return "a"
     }
      let f:()=>void=function(){
     }
    //函数声明
    function fn(x:number,y:number):number{
        return x+y
    }
    

    可选参数和参数默认值

    说明:通过?来定义可选参数
        function fn(x:Type,y?:Type):Type
        可选参数默认为undefined
        可选参数必须在必传参数之后
    //可选参数
    function fn(x:number,y?:number):number{
       return x+y
    }
    //参数默认值,其实因为类型推导,可直接写成y=1
    function fn1(x:number,y:number=1):number{
       return x+y
    }
    console.log(fn(1));//NaN
    console.log(fn1(1));//2
    补充:可选参数和默认值不要用在一个参数上
    

    剩余参数

    //剩余参数
    function fn2(...arg:any[]){
       console.log(arg) //[ 1, 2, 3 ]
    }
    fn2(1,2,3)
    

    函数重载

    //定义函数的重载格式
    function fn(x:number,y:string);
    function fn(x:number,y:number);
    //定义函数具体的实现
    function fn(x:any,y:any){
       console.log(x+y)
    }
    fn(1,2) //3
    fn(1,"2")//12
    

    ts中的this

    案例一:
    let obj={
       a:10,
       fn(){
           //函数中默认this指向是any,通过下面再配置文件中解决,而且如果是类似于
           //document中事件的this,ts会自动推导出类型,this指向不需要下面配置也是事件对象
          //  "noImplicitThis": true
          console.log(this.a)
            //注意:此时this的指向只是是否有提示的问题,真的执行代码配置文件设置不设置值都是10
       }
    }
    案例二:
    let obj={
       a:20,
       fn(this:Document){
          console.log(this.querySelector)
       }
    }
    document.onclick=obj.fn
    说明:如果配置配置了this指向"noImplicitThis": true,
    则fn中的this指向就是obj对象,但是此时obj.fn指向了
    点击事件,为了有提示信息,需要手动指定this指向this:Document
    这个this参数其实是一个假参数,ts编译时候会被去掉,纯粹是
    为了代码提示而存在,this指向配置不配置,修改不修改都不影响最后的结果
    

    修饰符

    public protected(该类和子类能访问) private(类,对象内部) readonly(类,对象内部可用,其他只读)

    案例一:
    class Person{
       readonly n:number;
       constructor(num:number){
          this.n=num;
       }
    }
    let p=new Person(20)
    案例二:简写方式
    class Person{
       constructor(public num:number){
          this.n=num;
       }
    }
    let p=new Person(20)
    说明:因为ts不同于js,构造函数中属性需要先声明才能
    使用,此时public num:number此种方式就是相当于提前再
    class中先声明了一份
    

    存取器

    class Person{
       //私有属性,大家默认的规则是下划线
       private _num:number;
       //存取器
       //存取器再ts中不是当做方法使用的,而是被当做属性
       get num():number{
          return this._num
       }
       set num(num:number){
          if(num>0){
             this._num=num;
          }
       }
    }
    let p=new Person()
    p.num=-10
    console.log(p.num);//undefined
    

    静态

    class Person {
       private static instance;
       private constructor() { }
       public static getInstance() {
          if (!Person.instance) {
             Person.instance = new Person();
          }
          return Person.instance;
       }
    }
    let p=Person.getInstance();//相等
    let p1=Person.getInstance();
    

    抽象类

    abstract class Person {
       constructor() { }
       abstract study():void;
    }
    class Student extends Person{
       study(): void {
          console.log("学习");
       }
    }
    let s=new Student();
    s.study()
    

    接口

    //接口不能有任何属性和方法实现,只能有抽象描述
    interface Options{
       num:number;
       //可选的
       name?:string;
       say();
    }
    class optImpl implements Options{
       num: number;
       constructor(num:number){
          this.num=num;
       }
       say() {
          console.log(this.num+"说话");
       }
    }
    function fn(opts:Options) {
       opts.say()
    }
    fn(new optImpl(20))
    

    断言

    interface Options{
       num:number;
       name:string;
    }
    
    function fn(opts:Options) {
    }
    //断言
    //按理说必须传入{num:20,name:"呵呵"}类似的才能通过
    //但是通过断言可强制判定传入参数是什么类型
    fn({} as Options)
    
    补充:
    let obj={
       num:10,
       name:"saa",
       a:1
    }
    fn(obj)
    说明:如果把传入的参数先赋值好在传入,可以避免规则检测
    不会报错,但是此种情况只能在传入的obj覆盖全部所需参数
    情况下,也就是说只能多不能少
    

    索引签名

    /**
     * 索引签名:
     *    希望规则是:一组由数字进行key命名的对象
     * 补充:索引签名的key类型只能是string或者number
     * 索引签名在下面传参时候,是可有可没有的,而且不限制个数
     */
    interface Options{
       //key是number,value是any类型的数据
       [atrr:number]:any;
    }
    
    function fn(opts:Options) {
    }
    fn({
       0:1,
       2:20
    })
    

    函数类型接口

    /**
     * 函数类型接口
     * 是一个包含由fn并且值的类型为函数的结构体
     * 并不是描述函数结构而是一个包含函数的对象结构
     */
    interface Options{
       fn:Function
    }
    let o:Options={
       fn:function(){
    
       }
    }
    
    /**
     * 下面约定就是函数结构,而不是包含有函数的对象结构了
     */
    interface IFn{
       (x:number):number
    }
    let fn:IFn=function(x:number){return x}
    
    
    /**
     * 下面是函数结构的实践
     *    因为interface的约定,保证了传参的正确性
     *    在编译阶段避免了出错
     */
    interface MouseEventCallBack{
       (e:MouseEvent):any;
    }
    let fn1:MouseEventCallBack=function(e:MouseEvent){}
    document.onclick=fn1;
    
    

    补充案例

    interface AjaxData{
       code:number;
       data:any;
    }
    interface AjaxCallBack{
       (rs:AjaxData):any
    }
    function ajax(callback:AjaxCallBack){
       callback({
          code:200,
          data:{}
       })
    }
    

    泛型

    /**
     * 泛型:
     *    很多时候,类型写死,不利于复用
     */
    //泛型变量
    function fn<T>(args:T):T{
       return args;
    }
    function fn1<T,S>(args:T,args1:S):[T,S]{
       return [args,args1];
    }
    
    //数组形式
    function fn2<T>(args:T[]):T[]{
       return args;
    }
    function fn3<T>(args:Array<T>){}
    

    泛型类

    class MyArray<T>{
       private _data:T[]=[];
       public push(v:T):number{
          return this._data.length;
       }
    }
    let a=new MyArray<string>();
    a.push("a")
    
    let b=new MyArray<number>();
    b.push(1)
    

    泛型类型

    //泛型类型
    let fn:<T>(x:T,y:T)=>number=function(x,y){
       return Number(x)+Number(y)
    }
    let fn1=function<T,S>(x:T,y:S):number{
       return Number(x)+Number(y)
    }
    console.log(fn(1,2));//3
    console.log(fn1<number,string>(1,"2"));//3
    

    泛型接口

    interface IFN<T,S>{
       (x:T,y:S):S
    }
    let fn2:IFN<string,number>=function(x,y){
       return Number(x)+Number(y);
    }
    

    类类型

    /**
     * 类类型:
     *    表示这个类型对应的对象
     */
    
     //错误实例:此时Array代表就是类类型,但是需要的参数是该类
     //对应的构造函数
    function getArray1(constructor:Array<number>){
       return new constructor();
    }
    getArray2(Array)
    
    //补充:p后面的Person就是类类型
    let p:Person=new Person();
    //下面是构造函数
    let fn1:{new ():Person}
    
    
    //正确写法
    function getArray2(constructor:{new():Array<string>}){
       return new constructor();
    }
    getArray2(Array)
    

    泛型约束

    形式一:
    function fn<T extends number>(a:T){
       console.log(a);
    }
    
    形式二:
    interface Len{
       length:number
    }
    function fn1<T extends Len>(a:T){
       console.log(a.length);
    }
    fn1("a")//此时在fn1(1)则会报错,因为数字类型没有length属性
    

    装饰器

    基本案例:
    //配置文件(开启装饰器):"experimentalDecorators": true
    /**
     * 类装饰器:
     *    类装饰器用于构造函数,可以用来监视,修改或者替换类定义
     *    类的构造函数会作为类装饰器函数的唯一参数
     *    function f(constructor:Function){}
     */
    
    function f<T extends {new (...args:any[]):{}}>(constructor:T):T{
       class P extends constructor{
          age=20
       }
       return P;
    }
    
    //f是装饰器函数,属于类装饰器,会自动调用,并且传入对应类
    //的构造函数
    @f
    class Person{
       name="qiang"
    }
    let p=new Person();
    //从打印结果可知,其实p已经是P而不是Person了
    console.log(p);//P { name: 'qiang', age: 20 }
    

    类装饰器参数

    function f(v:number){
       return function f1<T extends {new (...args:any[]):{}}>(constructor:T):T{
          class P extends constructor{
             age=v;
          }
          return P;
       }
    }
    
    
    @f(10)
    class Person{}
    let p=new Person()
    console.log(p);//P { age: 10 }
    说明:类装饰器修饰的类其实都是新类,例如此时是P而不是Person
    因为类装饰器是js自动调用的,顾不可以加(),但是为了参数
    可以利用闭包,返回真实类装饰器,通过间接方式传参
    

    方法装饰器

    class Greeter {
        greeting: string;
        constructor(message: string) {
            this.greeting = message;
        }
        @enumerable(false)
        greet() {
            return this.greeting;
        }
    
    }
    function enumerable(value: boolean) {
        /**
         * target:对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。
           propertyKey:成员的名字(说白了,方法名)
            descriptor: 成员的属性描述符,例如:是否可编辑,可修改,可读可写等
                descriptor.value:就是贝装饰器修饰的方法==target.propertyKey
         * */
        return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
            let fn=descriptor.value;
            descriptor.value=function(){
                console.log("1");
                //因为this绑定的原因,如果此处不给fn绑定this,则返回指是underfined
                //而且当前this就是对应的对象或者类(静态成员的话)
                let a=fn.apply(this);
                console.log(a);
                //不能通过下面方法调用,,否则会形成无止境的递归
                // descriptor.value.apply(this)
                console.log("2");
                
            }
        };
    }
    let g=new Greeter("abbb");
    g.greet()
    

    相关文章

      网友评论

          本文标题:TypeScript基础

          本文链接:https://www.haomeiwen.com/subject/evtrcqtx.html