zoukankan      html  css  js  c++  java
  • 【专项学习】—— Typescript语法进阶

    一、TypeScript中的配置文件

    ①生成tsconfig.json文件

    npm install typescript -g
    
    tsc init
    

    ②tsconfig.json文件的作用是typescript对应的编译配置文件 

    ③运行tsc demo.ts会编译成demo.js文件

    ④只有单独输入tsc命令,后面不跟任何参数时,才会执行tsconfig里面的配置

       ts-node demo.ts也会执行tsconfig里面的配置项

    ⑤compilerOptions前(或后)添加include指定想要编译的文件 

    "include": ["./demo.ts"]
    
    同"files":["./demo.ts"]
    

    也可以写exclude指定编译所有内容所要排除不编译的文件

    "exclude": ["./demo.ts"]
    

    ⑥compilerOptions是编译属性配置项  

       "removeComments": true,   //移除注释
    
       "noImpliciAny": true,    //不明确的指定any类型不行
    
       "stictNummChecks": true,    //强制检测Null类型,将null赋值给基础类型会报错
    
       "rootDir": "./src",    //指定输入文件的地址
    
       "outDir": "./build",  //指定编译后生成文件的地址
    
       "incremental": true,  //增量编译,以前编译过的内容不会再编译,只编译新增的文件
    
       "allowJs": true,    //是否对js文件也进行编译,把ES6语法编译为ES5语法文件
    
       "checkJs": true,   //允许对js文件像ts文件一样进行语法检测
    

    二、联合类型和类型保护

    interface Bird {
      fly: boolean;
      sing: () => {};
    }
    
    interface Dog {
      fly:boolean;
      bark: () => {};
    }
    
    //联合类型 - 属性只会取共有的属性
    function trainAnimal(animal: Bird | Dog ) {
       //1.类型断言 — 类型保护,规避typescript的潜在错误提示
       if(animal.fly) {
          (animal as Bird).sing();
       }else{
          (animal as Dog).bark()
       }
       
    }
    
    function trainAnimalSecond(animal: Bird | Dog) {
      //2.in语法 - 类型保护
      if('sing' in animal) {
        animal.sing();
      }else{
        animal.bark();
      }
    }
    
    function add(first: string | number, second: string | number) {
      //3.typeof 语法 - 类型保护 
      if(typeof first === 'string' || typeof second === 'string'){
         return `${first}${second}`;
       }
       return first + second;
    }
    
    //只要class 才能被instanceof操作符使用,interface不能
    class NumberObj {
      count: number
    }
    
    function addSecond(first: object | NumberObj, second: object | NumberObj){
      //4.instanceof 语法 - 类型保护
      if(first instanceof NumberObj && second instanceof NumberObj){
        return first.count + second.count
      }
      return 0;
    }
    

    三、Enum枚举类型 

    ①初始化项目,生成package.json

    npm init -y  

    ②安装ts-node依赖

    npm install ts-node -D  

    ③package.json中添加命令

    "dev": "ts-node ./demo.ts"  

    ④安装typescript

    npm install typescript --save
    

    ⑤Enum枚举类型应用  

    enum Status {
      OFFLINE,
      ONLINE,
      DELETED
    }
    
    // const Status = {
    //   OFFLINE: 0,
    //   ONLINE: 1,
    //   DELETED: 2
    // }
    
    function getResult(status) {
      if(status === Status.OFFLINE) {
        return 'offline';
      }else if(status === Status.ONLINE){
        return 'online';
      }else if(status === Status.DELETED){
        return 'deleted';
      }
      return 'error'
    }
    
    const result = getResult(Status.OFFLINE);
    console.log(result);  //offline
    

      

      

     

    四、函数泛型

    //泛型 generic 泛指的类型
    
    //T可以是任何类型的泛型
    function join<T, P>(first: T, second: P) {
      return `${first}${second}`;
    }
    
    join<number, string>(1, '1');
    
    // T[]
    function map<T>(params: Array<T>){
      return params;
    }
    
    map<string>(['123']);
    

      

    五、类中的泛型类型以及泛型类型

    ①类中的泛型类型

    interface Item {
      name: string;
    }
    
    class DataManager<T extends Item> {
      constructor(private data: T[]) {}
      getItem(index: number): string {
        return this.data[index].name;
      }
    }
    
    // const data = new DataManager<number>([1]);
    // data.getItem(0);
    
    const data = new DataManager([
      {
        name: 'dell'
      }
    ])
    
    class DataManager<T extends number | string> {
      constructor(private data: T[]) {}
      getItem(index: number): T {
        return this.data[index]
      }
    }
    
    // const data = new DataManager<string>([]);
    const data = new DataManager<number>([]);
    

    ②泛型声明的type类型  

    // const func: <T>() => string = <T>() => {
    //   return '123'
    // }
    
    //如何使用泛型作为一个具体的类型注解
    function hello<T>(param: T) {
      return param
    }
    
    const func: <T>(param: T) => T = hello;
    

    六、命名空间namespace  

    ①tsconfig.json

        "outDir": "./dist",             
        "rootDir": "./src", 
    

    ②index.html  

    <!DOCTYPE html>
    <html lang="en">
      <head>
         <meta charset="UTF-8" />
         <title>Document</title>
         <script src='./dist/page.js'></script>
      </head>
      <body>
         <script>
            new Home.Page();
         </script>
      </body>
    </html>
    

    ③src->page.ts: Home命名空间中,export暴露出要用的page,index.html中就可以使用new Home.page();其它方法不使用则不暴露  

    namespace Home {
      class Header {
        constructor() {
          const elem = document.createElement('div');
          elem.innerText = 'This is Header';
          document.body.appendChild(elem);
        }
      }
      
      class Content {
        constructor() {
          const elem = document.createElement('div');
          elem.innerText = 'This is Content';
          document.body.appendChild(elem);
        }
      }
      
      class Footer {
        constructor() {
          const elem = document.createElement('div');
          elem.innerText = 'This is Footer';
          document.body.appendChild(elem);
        }
      }
      
      export class Page {
        constructor() {
          new Header();
          new Content();
          new Footer();
        }
      }
    }
    
    • 拆分页面和组件多个命名空间

    ①tsconfig.json 

    "outFile": "./dist/page.js" , //把所有要输出的文件联合起来输出一个单一的文件  

    此时会有报错,因为设置了outFile后只支持amd或system的规范,不支持commenjs的规范了

    "module": "amd",
    

    ②index.html不变

    ③src->page.ts依赖conponents.ts

    //依赖声明
    ///<reference path="./components.ts" />
    
    namespace Home {
      export class Page {
        user: Components.User = {
          name: 'dell'
        }
        constructor() {
          new Components.Header();
          new Components.Content();
          new Components.Footer();
        }
      }
    }
    

    ④src->components.ts暴露给page.ts所需要的方法和子命名空间  

    namespace Components {
      
      //子的命名空间
      export namespace SubComponents {
        export class Test {}
      }
    
      export interface User {
        name: string;
      }
    
      export class Header {
        constructor() {
          const elem = document.createElement('div');
          elem.innerText = 'This is Header';
          document.body.appendChild(elem);
        }
      }
      
      export class Content {
        constructor() {
          const elem = document.createElement('div');
          elem.innerText = 'This is Content';
          document.body.appendChild(elem);
        }
      }
      
      export class Footer {
        constructor() {
          const elem = document.createElement('div');
          elem.innerText = 'This is Footer';
          document.body.appendChild(elem);
        }
      }
    }
    

    ⑤问题:page.ts中依赖的Components命名空间必须在打开其它文件后才可以追溯到  

    七、import对应的模块化  

    ①src->components.ts:export暴露三个变量  

    export class Header {
        constructor() {
          const elem = document.createElement('div');
          elem.innerText = 'This is Header';
          document.body.appendChild(elem);
        }
    }
      
    export class Content {
      constructor() {
        const elem = document.createElement('div');
        elem.innerText = 'This is Content';
        document.body.appendChild(elem);
      }
    }
    
    export class Footer {
      constructor() {
        const elem = document.createElement('div');
        elem.innerText = 'This is Footer';
        document.body.appendChild(elem);
      }
    }
    

    ②src->page.ts:import导入components的变量,export default最终要用到的Page  

    import { Header, Content, Footer } from './components'
    
    export default class Page {
        constructor() {
          new Header();
          new Content();
          new Footer();
        }
    }
    

    ③问题:'define' is not defined,原因是现在打包生成的文件是amd规范,浏览器不识别define()语法  

     

     ④index.html中引入require.js,帮助识别define()语法;

    <!DOCTYPE html>
    <html lang="en">
      <head>
         <meta charset="UTF-8" />
         <title>Document</title>
         <script src='https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.6/require.js'></script>
         <script src='./dist/page.js'></script>
      </head>
      <body>
         <script>
           require(['page'], function(page) {
             new page.default()
           })
         </script>
      </body>
    </html>
    

    八、使用parcel打包TS代码  

    ①安装parcel@next打包工具

    npm install parcel@next -D  

    ②package.json中修改test命令

    "test": "parcel ./index.html"  

    ③运行npm run test,开启一个服务器地址http://localhost:1234

    九、描述文件中的全局类型

    ①index.html中引用jquery的CDN文件

    <!DOCTYPE html>
    <html lang="en">
      <head>
         <meta charset="UTF-8" />
         <title>Document</title>
         <script src='https://cdn.bootcss.com/jquery/3.4.1/jquery.js'></script>
         <script src='./page.ts'></script>
      </head>
      <body>
      </body>
    </html>
    

    ②jquey语法在typescript中没有注解,需要写一个类型定义文件,打通ts文件和js文件之间的鸿沟  

    ③src->page.ts:使用jqurey写js语句

    // $(function() {
    //   alert(123);
    // })
    
    $(function() {
      $('body').html('<div>123</div>')
    })
    

    ④src->jquery.d.ts:类型注解文件  

    //declare 声明 - 定义全局变量
    // declare var $ : (param: () => void) => void;
    
    //declare 声明 - 定义全局函数
    declare function $(param: () => void): void;
    
    //函数重载:参数不同,允许对一个函数名字写多个函数声明
    declare function $(param: string): {
      html: (html: string) => {}
    }
    

     问题:jquery函数返回的应该也是一个jqury对象,不能指定为{}

    //定义全局函数
    interface JqueryInstance {
      html: (html: string) => JqueryInstance;
    }
    
    declare function $(readyFunc: () => void): void;
    declare function $(selector: string): JqueryInstance;
    

    使用 接口语法 写函数重载  

    //定义全局函数
    interface JqueryInstance {
      html: (html: string) => JqueryInstance;
    }
    
    //使用interface的语法,实现函数重载
    interface JQuery {
      (readyFunc: () => void): void;
      (selector: string): JqueryInstance;
    }
    
    declare var $: Jquery;
    
    • 如何对对象进行类型定义,以及对类进行类型定义,以及命名空间的嵌套

    ①page.ts:在使用$('body')时,相当于执行了new $.fn.init();  

    $(function() {
      $('body').html('<div>123</div>');
      new $.fn.init(); //构造函数 才能用new语法
    })
    

    ②jquery.d.ts  

    //定义全局函数
    interface JqueryInstance {
      html: (html: string) => JqueryInstance;
    }
    
    //函数重载
    declare function $(readyFunc: () => void): void;
    declare function $(selector: string): JqueryInstance;
    
    //如何对对象进行类型定义,以及对类进行类型定义,以及命名空间的嵌套
    declare namespace $ {  //$ 是命名空间
      namespace fn {       //fn 是命名空间
        class init {}      //init 是构造函数
      }
    }
    

    十、模块代码的类型描述文件  

     ①安装jquery 

    npm install jquery  --save
    

     ②page.ts:import引用jquery,会提示报错,找不到jquery module  

    import $ from 'jquery';
    
    $(function() {
      $('body').html('<div>123</div>');
      new $.fn.init(); //构造函数 才能用new语法
    })
    

    ③jquery.d.ts: 通过module定义一个jquery的模块,定义关于$混合类型的内容,最终export导出要使用的$ 

    //ES6 模块化
    declare module 'jquery' {
      //定义全局函数
      interface JqueryInstance {
        html: (html: string) => JqueryInstance;
      }
    
      //$ 混合类型 - 不必再写declare, 直接写function即可
      function $(readyFunc: () => void): void;
      function $(selector: string): JqueryInstance;
    
      namespace $ {  //$ 是命名空间
        namespace fn {       //fn 是命名空间
          class init {}      //init 是构造函数
        }
      }
    
      export = $;
    }
    

    十一、泛型中keyof语法的使用  

    interface Person {
      name: string;
      age: number;
      gender: string;
    }
    
    class Teacher {
      constructor(private info: Person) {}
      getInfo(key: string){
        //类型保护
        if(key === 'name' || key === 'age' || key === 'gender'){
          return this.info[key];
        }
      }
    }
    
    const teacher = new Teacher({
      name: 'dell',
      age: 18,
      gender: 'male'
    })
    
    const test = teacher.getInfo('name');
    console.log(test)
    

    问题:test的可能类型会是string | number | underfind,是因为传任何值给getInfo方法时,key值不定

                typescript不会深度分析,传入的是不是name类型,如果是则值必须是string类型;传入的是age类型,值必须是number类型

    解决:通过泛型结合keyof语法  

    interface Person {
      name: string;
      age: number;
      gender: string;
    }
    
    //第一次循环
    //T extends 'name'
    //type T = 'name'
    //key: 'name'
    //Person['name'];  //string
    
    //第二次循环
    //T extends 'age'
    //type T = 'age'
    //key: 'age'
    //Person['age'];   //number     
    
    class Teacher {
      constructor(private info: Person) {}
      getInfo<T extends keyof Person>(key: T): Person[T]{
        return this.info[key];
      }
    }
    
    const teacher = new Teacher({
      name: 'dell',
      age: 18,
      gender: 'male'
    })
    
    const test = teacher.getInfo('name');
    console.log(test)
    

    注:课程源自慕课网 

    人与人的差距是:每天24小时除了工作和睡觉的8小时,剩下的8小时,你以为别人都和你一样发呆或者刷视频
  • 相关阅读:
    DataGrid内容导出Excel文件(C#)
    IE无法查看源文件原因及解决办法
    通过Internet访问内网中的服务器
    工欲善其事,必先利其器——图文并茂详解VisualStudio使用技巧
    Flash中对动态文本框使用遮罩
    Flash中XML跨域访问数据的规则
    Google导航代码
    信息竞赛小结
    第一天,开始系统学习 void
    浅析各种数据类型的取值范围 void
  • 原文地址:https://www.cnblogs.com/ljq66/p/14518188.html
Copyright © 2011-2022 走看看