TypeScript 入门学习 ts代码检查 AMD CMD UMD ESM初步了解概括

随手一提

javaScript 脚本语言 借助宿主环境运行 网页浏览器 / node环境

typeScript基础:

原始数据类型

任意值类型:

如果是 any 类型,则允许被赋值为任意类型

类型推论:

      let myFavoriteNumber;
      myFavoriteNumber = 'seven';
      myFavoriteNumber = 7;

如果定义时没有赋值 不管之后有没有赋值 都会被推断成any类型 完全不被类型检查

联合类型:

  1. 联合类型用 | 分隔 let myFavoriteNumber:string | number
  2. 当不确定联合类型的变量 是哪个类型的时候 只能访问联合类型的共有属性或者方法

对象类型——接口

  1. 例子:
interface Person {
      name:string;
      age:number;
}

let tom:Person = {name:'asad', age:23}

  1. 赋值的时候 变量的形状必须和接口的形状保持一致(初始整体赋值时) 变量比接口少一些或多一些属性不被允许

  2. 可选属性 不完全匹配时

  inteface Person {
    name:string;
    age?:number
  }
  1. 任意属性
```js
interface Person {
  name:string;
  age?:number,
  [propName:string]:any
}

interface Person {
  name:string;
  age?:number,
  [propName:string]:string
}

let  tom:Person = {
  name:'tom',
  age:24,
  gender:'male'
}

//任意属性的值允许是string  但是可选属性 age:number 不是string 的子属性

```
一旦定义了任意属性  确定属性和可选属性的类型必须是它的类型的子继
一个接口中只能定义一个任意属性 接口中有多个类型的属性 可以在任意属性中使用联合类型
```js
interface Person {
  name:string;
  age?:number;
  [propName:string]:string|number
}
```
  1. 只读属性 readonly
```js
  interface Person {
    readonly id: number;
    name: string;
    age?: number;
    [propName: string]: any;
}


  let tom: Person = {
      id: 89757,
      name: 'Tom',
      gender: 'male'
  };

  tom= {
     //id:1212,  //注销  报错 !!  Property 'id' is missing in type '{ name: string; }' but required in type 'Person'.
     name:'2ee',
   // gender:'male'
  }

  tom.id = 2112  //报错!! Cannot assign to 'id' because it is a read-only property.
```
  属性id 是只读属性  在整体赋值时 必须带上  第一次整体赋值 还是后整体赋值 
  属性id 单独赋值时   报错

数组的类型

  1. 例子
    
    let  workers :number[] = [1,2,3,1,3]
    
  2. 数组的泛型
 let  powers :Array<number> = [3,4,5,1,4]

  1. 用接口表示数组
  2. 类数组
    类数组不是数组类型 不能用普通数组的方式描述 而应该用接口
          let args:{
            [index :number]:number;
            length:number;
            callee:Function;
          }= arguments;
    
    
    类数组都有自己的接口定义 如 IArguments, NodeList, HTMLCollection
    function sun () {
    
      let args:IArguments = arguments;
    }
      // IArguments 是TypeScript 定义好的类型 
      interface IArguments {
        [index : number]:any;
        length:number;
        callee:Function;
      }
    
    1. 数组 any
      any 数组中允许出现任意类型:
      let list: any[] = [{class:'dqw'},'21',1]
      

函数的类型

  1. 函数声明2种形式
    函数声明 function Declaration
    函数表达式 function Expression

    function sum(x,y){
      return x+y;
    }
    
    let mus = function(x,y){
      return x+y;
    }
    
    function sum(x:number,y:number):number{
      return x+y
    }
    
  2. 函数表达式

    let mus:(x:nummber,y:number)=>number= function(x:number,y:number){
      return x+y;
    }
    
  3. 接口定义函数的形状 有点复杂&%&#

  4. 函数可选参数
    可选参数后面不允许再出现必需参数

       function buildName(firstName?:string,lastName:string){
          if(firstName)...
          else return ...
       }
    
       let tom = buildName(undefined,'tom')
    
  5. 参数默认值
    默认值的参数 被视为可选参数 此时这个可选参数位置不受限制

    function buildName (firstName:string = 'Tom' , lastName : string){
      return firstName + '' +lastName;
    }
    let cat = buildName(undefined,'Cat');
    
  6. 剩余参数(rest参数) 是数组类型

    function push(array:any[], ...items:any[]){}
    
  7. 重载

类型断言

  1. type Assertion : 手动指定一个值的类型
  2. 语法 2 种形式
             值 as 类型 

             <类型>值
  1. 断言用法

    1. 联合类型断言为其中一个类型
       interface Fish {
         name:string;
         swim():void;
       }
    
       interface Cat {
         name:string;
         run():vold;
       }
    
       function isCat(animal:Cat | Fish ):boolean{
         if(typeof (animal as Cat).run==='Function'){
                return true;
         }else{
           return false;
         }
       }
    
     2. 父类型断言为子类型
       class  ApiError  extends Error {
            code :number =0;
       }
    
       class HttpError extends Error {
         status :number = 200;
       }
    
       function isApierror (error :Error ){
    
         if(typeof (error as ApiError).code === 'number'){
           return true;
         }
         return false;
       }
    
       等价于   error instanceof  ApiError
    
       当 ApiError 和 HttpError 是接口时  不能使用 instanceof, 接口是一个类型  ts编译过后直接删除 类型, js运行时没有类型  则使用instanceof会报错
    
     3. 将任何一个类型断言为 any
        有时候非常确定 一段代码不会报错 
    
        window.foo = 3;   // ts编译时 会报错 提示 window上没有这个属性 
        (window as any).foot = 3;
        
        -在any上访问任何属性都是允许的
        -TypeScript设计理念之一:我们需要在类型严格性和开发便利性之间掌握平衡
    
     4. 将any 断言为一个具体类型
    
  2. 类型断言的限制

    • 要使得A被断言成B,只需要A兼容B或B兼容A即可
    • 若A兼容B,那么A能够被断言成B,B也能够被断言成A
  3. 双重断言

    1. 任何类型都能被断言为any
    2. any可以被断言成任何类型
    
    interface Cat {
      run():void;
    }
    
    interface Fish{
      swim():void;
    }
    
    function test (cat :Cat){
    
      return (cat as any as Fish);  //报错 Cat 与 Fish 互不兼容
    }
    
    3. 违背限制,触发迫不得已,千万别用双重断言
    
    
  4. 类型断言 vs 类型转换
    类型转换还是要调用类型转换的方法
    类型断言只会影响ts编译是的类型,在编译结果中会被删除:

    function  toBoolean(something :any):boolean {
      return something as boolean;
    }
    
    toBoolean(1);//返回1  
    
    function toBoolean (something:any):boolean{
      return Boolean(something);
    }
    
    
  5. 类型断言 vs 类型声明

    • animal 断言为 Cat, 只需要满足Animal兼容Cat 或 Cat兼容Animal即可
    • animal 赋值给 tom(Cat类型),要满足 Cat兼容 Animal
    • Cat不兼容Animal 不能将父类的实例赋值给类型为子类的变量
    • "兼容" 换成 "包括" 更容易理解
    • 子类不能包括父类

泛型

  1. 定义:Generics 是指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候在指定类型的一种特性

// 泛型类

class KeyValuePair<T> {
  constructor(public key: T, public value: string) { }
}


let pair = new KeyValuePair<string>('1', 'w');


//通用类  K  V
class KeyValue<K, V>{
  constructor(public key: K, public value: V) { }
}

let pair1 = new KeyValue<string, string>('1', '6')




//泛型函数

function warpInArray(value: number) {
  return [value];
}

let numbers = warpInArray(1);// 返回数字类型数组

//通用

function warpInArray1<T>(value: T) {
  return [value];
}

class ArrayUntils {

  static warpInArray1<T>(value: T) {
    return [value];
  }
}

let numbers1 = ArrayUntils.warpInArray1(1);


//泛型接口

//http://mywebsite.com/users
//http://mywebsite.com/products

interface Result<T> {
  data: T | null,
  error: string | null
}


function fetch<T>(url: string): Result<T> {
  return { data: null, error: null };
}


interface User {
  username: string;
}

interface Product {
  title: string;
}


let result = fetch<User>('url');

result.data.username

let res1 = fetch<Product>('url')
res1.data.title

//泛型约束

function echo<T>(value: T): T {
  return value;
}

echo('1');   //类型推断  echo<string>('1')


function echo1<T extends number | string>(value: T): T {
  return value;
}

echo1('1');  //只能传递 number 或者 string 类型参数


// 只能传递这个形状的对象
function echo2<T extends { name: string }>(value: T): T {
  return value;
}

echo2({ name: 'a' })


interface Person {
  name: string;

}



function echo3<T extends Person>(value: T): T {
  return value;
}


//可以用 calss 约束

class Person {
  constructor(public name: string) { }
}


class Custumer extends Person {

}


echo(new Person('a'))
echo(new Custumer('b'))  // 实例间接的来源于 Person



// 扩展泛型类
// 泛型和继承

interface Product {
  name: string;
  price: string;
}

class Store<T> {
  protected _objects: T[] = [];

  add(obj: T): void {

    this._objects.push(obj);
  }

}

// let store = new Store<Product>();
// store.objects=[];

//在 CompressibleStore 后添加 <T> 编译器知道了  store 后的 <T>的来源

// 传递泛型类型的参数  Pass on  the generic type parameter 
// 1. 基类中的泛型类型参数 也可被使用在 类中
class CompressibleStore<T> extends Store<T>{
  compress() { }
}


let store = new CompressibleStore<Product>()
// store 有2个方法  compress  add

// class SearchableStore<T> extends Store<T> {
//   find(name: string): T | undefined {
//     return this._objects.find(obj => obj.name === name);  //此处报错  Propert 'name' does not exist on type 'T'  编译器不知道T 有name属性
//   }
// }



// T 泛型约束  可以使用具有name 属性的任何类型的对象
// 2. 限制泛型类型参数 Restrict the genertic type parameter
class SearchableStore<T extends { name: string }> extends Store<T>{ }

//3. Fix the generic type parameter
//具体的类型  不需要泛型
class ProductStore extends Store<Product> {
  filterByCategory(category: string): Product[] {
    return [];
  }
}


//泛型类型有默认值

声明文件

  1. *.d.ts文件
  2. 全局的声明 局部模块声明
  3. 全局声明 :declare关键字 配合 tsconfig.json中 include 、 exclude、 file 默认加载
  4. 局部模块: 含有export/import关键字 模块内
    • npm 包类型声明:
      • axios 包 引入 axios时,假设没有对应的类型声明文件,引入会报错
      • 配合 tsconfig.json 中的path 即export function createInstance(): AxiosInstance 引入axios自动加载 path中:[ "axios": types/axios.d.ts] 中ts文件
      • export interface XXX 结合declare使用 此时 declare不会声明一个全局变量
    • npm 包扩展:
      • 如果是需要扩展原有模块的话,需要在类型声明文件中先引用原有模块,再使用 declare module 扩展原有模块
  5. 例子
    // String 扩展一个方法
    
    interface String {
     hello:()=>any;
    }
    
    "a".hello();
    
    
    

前端模块化

  1. CommonJs module.exports require 同步加载
  2. AMD define require 异步加载、依赖前置
  3. CMD define seajs(requirejs) 异步加载、依赖就近
  4. UMD 结合 AMD + CommonJs
  5. ESM(ES6 Module) export import
  • 服务端: CommonJs 、 UMD(AMD + CommonJS)

  • 浏览器: AMD、 CMD、 ESM

  • Commonjs

    //a.js
      module.exports = {
         a: function (msg){console.log(msg)}
      }
    
    // b.js引用
    const a = require ('./a.js')
        a.a('sc')  
    
  • AMD

    • AMD在浏览器端异步加载,AMD推崇依赖前置,加载完模块之后就会立即执行它
    • 例子
    //https://blog.csdn.net/weixin_38407447/article/details/117407660 AMD 异步加载机制
     
     // amd.js 类似于 require.js 建立requir函数  define函数  require.config 函数等
     function define(...arr){}
     function require(deps,acllback){
      return new Promise(saync (resolve ,reject)=>{}).then(e =>{return callback(...e)})
     }
    
     // a.js模块 依赖b模块  此处b模块不写
     define('a',['b'],function(b){
      return {run : function(){return 'ssa'}}
     })
    
    //AMD用法  amd.html
          <html>
          <head>
          <meta charset="UTF-8">
          <script  src= './amd.js'></script>   //类似引用require.js
          </head>
          <body>
          
          </body>
    
          <script>
                      require.config({
                        path:{
                          'lodash':"https://cdn.XXXX/XXX/lodash.js"
                        }
                      })
    
                      require(['lodash','a'],function(lodash,a){ ...})
          </script>
          </html>
    
    • CMD
      • CMD在浏览器端异步加载,CMD推崇依赖就近,加载完模块不会立即执行,只是加载,等到需要的时候才会执行
      • 例子
      define(function(require,exports,module){
       var $ = require('jquery.js')    //按需执行
       var add = function(a,b){return a+b} 
      })
    
      exports.add = add;
    

内置对象

类别别名

字符串字面量类型

类与接口

  1. 类实现接口 可以实现多个接口 类只能继承一个类
  2. 接口继承接口 多个
  3. 接口继承类 TypeScript中可以

代码检查

  1. TypeScript 自带 ts检测 \ 还要使用ESlint

  2. eslint 能够发现出一些 tsc 不会关心的错误,检查出一些潜在的问题,所以代码检查还是非常重要的

  3. TypeScript中使用ESlint

    • 安装 npm install --save-dev eslint
    • 安装 ESlint 解析 ts解析器 npm install --save-dev typescript @typescript-eslint/parser
    • 安装 额外的适用于 ts 语法的规则 npm install --save-dev @typescript-eslint/eslint-plugin
    • 创建配置文件对哪些规则进行检查 .eslintrc.js 或者 .eslintrc.json
  4. 检查一个ts文件

    • 执行 ./node_modules/.bin/eslint index.ts (不是全局eslint脚本)
    • 检查整个项目的ts文件
                {
              "scripts": {
                  "eslint": "eslint src --ext .ts"
              }
          }
      
      
  5. VScode集成ESlint检查

    • 编辑器中集成eslint检查,可以在开发过程中发现错误,甚至保存后自动修复
    • 安装eslint 插件
    • VSCode 中的 ESLint 插件默认是不会检查 .ts 后缀的,需要在「文件 => 首选项 => 设置 => 工作区」中(也可以在项目根目录下创建一个配置文件 .vscode/settings.json),添加以下配置:
      {
        "editor.codeActionsOnSave": {
            "source.fixAll.eslint": true
          },
        "eslint.validate": [
            "javascript",
            "javascriptreact",
             {
            "language": "typescript",
            "autoFix": true
             },
        ],
        "typescript.tsdk": "node_modules/typescript/lib"
      }
      
      
  6. Prettier修复格式错误

    • 安装 npm install --save-dev prettier
    • 创建 prettier.config.js
    • vscode中 settings.json 配置
    • eslint 检查代码格式问题避免与prettier冲突 禁用掉 eslint相关代码格式规则
  7. 使用 AlloyTeam 的 ESLint 配置

 - npm install --save-dev eslint typescript @typescript-eslint/parser @typescript-eslint/eslint-plugin eslint-config-alloy

三斜杠

  1. ///
  2. 作用:
    • 声明文件中 代替import
    • 书写全局变量声明文件时
      // types/jquery-plugin/index.d.ts
      
               /// <reference types="jquery" />
      
               declare function foo(options: JQuery.AjaxSettings): string;
      
               // src/index.ts
      
               foo({});
      
      
  • 依赖一个全局变量的声明文件

参考

TypeScript入门

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,776评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,527评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,361评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,430评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,511评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,544评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,561评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,315评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,763评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,070评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,235评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,911评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,554评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,173评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,424评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,106评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,103评论 2 352

推荐阅读更多精彩内容