学习笔记(五)——TypeScript 语言

强类型与弱类型(类型安全维度)

语言层面限制

  • 强类型:不允许任意的数据隐式类型转换
    • 在编码阶段就能提示类型错误,可以更早暴露错误
    • 可以提高代码效率和准确性(可以提供更准确的智能提示)
    • 使重构更便捷可靠
    • 可以减少不必要的类型判断
  • 弱类型:允许任意的数据隐式类型转换
    • 只能在代码运行阶段才能发现问题
  • JavaScript是弱类型语言,Python是强类型语言

静态类型与动态类型(类型检查维度)

  • 静态类型:变量类型在声明时确定,之后不允许再修改
  • 动态类型:变量在运行阶段才能确定,且可以进行修改
  • JavaScript是动态类型语言,Python是动态类型语言

解释型与编译型

  • 解释型:代码运行时解析执行(脚本语言)
  • 编译型:需要预先编译,再执行编译输出的可执行文件

JavaScript类型系统特征

JavaScript是动态类型 弱类型 解释型脚本语言

Flow

由Facebook于2014年推出的JavaScript的类型检查器

  • 安装

    • yarn add flow-bin --dev
    • yarn flow init 初始化flow并生成配置文件 .flowconfig
  • 使用

    • 在JS文件开头添加注释 //@flow
    • 在相应的变量、参数后添加类型注解(冒号及类型)
    • 执行 yarn flow 检查
      • 会启动后台服务监控JS文件
    • 执行 yarn flow stop 停止后台服务
  • 编译移除类型注解

    • flow-remove-types

      • yarn add flow-remove-types --dev 安装
      • yarn flow-remove-types src -d dist 指定路径输出编译移除后的JS文件
    • babel

      • yarn add @babel/core @babel/cli @babel/present-flow 安装

      • 添加配置文件.babelrc

        {
            "presents": ["@babel/present-flow"]
        }
        
      • yarn babel src -d dist 指定路径输出编译移除后的JS文件

  • 开发工具插件

    • VSCode插件:flow-language-support
    • 其他IDE插件支持情况查看flow官网的编辑器支持
  • flow类型推断

    • 可以根据代码实际使用情况自行推断变量的类型,而可以不指明类型注解
  • flow类型注解

    • 在相应的变量、参数后添加冒号及类型
  • flow的类型

    • 原始类型
      • string
      • number
      • boolean
      • null
      • undefined
        • 使用void表示
      • symbol
    • 数组类型
      • Array<number>
      • number []
      • [string, number] :元组
    • 对象类型
      • { foo?: string, bar: number }
        • 限制必须存在特定属性,并限定该属性的类型
        • 属性名加问号,表示该属性可选,如果存在该属性,则属性类型必须为指定的类型
      • { [string]: string }
        • 限制对象key-value键值对类型,不限制属性数量
    • 函数类型
      • (string, number) => void
        • 指定参数及返回值类型
    • 特殊类型
      • 字面量类型:a: 'foo' = 'foo'
        • 限定变量值只能是特定值
      • 联合类型:使用 | 分隔多个类型
        • 字面量类型联合:type: 'success' | 'warning' | 'danger' = 'success'
          • 限定只能是特定可选值之一
        • 类型联合:a: string | number = 100
          • 限定只能是可选类型之一
      • 类型别名
        • type StringNumber = string | number
        • a: StringNumber = 'string'
      • maybe类型
        • 类型前加问号 a: ?number = undefined
        • 等同于 a: number | null | void
    • Mixed与Any
      • 可以接收任意类型
      • Mixed:强类型
        • 虽然可以接收任意类型,但是需要先明确变量是什么类型,才能进行相应的使用
      • Any:弱类型
        • 接收任意类型,并可以任意进行使用
        • 主要为了用来兼容未进行强类型校验的老代码
  • 运行环境API

TypeScript

TypeScript是JavaScript的超集,在JavaScript基础上扩展了类型系统ES6+新特性

  • 优点:

    • 类型系统使代码可靠性更高,同时可以使用ES6+新特性
    • 兼容性好,可以在任何使用JavaScript开发的环境使用TypeScript
    • 生态健全、完善
    • 渐进式,可以只使用部分特性
  • 缺点:

    • 增加了很多概念,例如:接口、枚举、泛型
    • 需要编写大量类型声明,对小型项目会增加开发成本
  • 安装

    • yarn add typescript --dev
  • 执行

    • yarn tsc typescript.ts
      • 编译 typescript.ts 为 typescript.js 文件
      • 进行类型检查
      • 移除类型注解
      • 转换ES6+语法为ES3语法
  • 配置文件

    • yarn tsc --init 初始化创建配置文件 tsconfig.json
    • 配置项
      • target
        • 指定转换为什么版本的ES标准代码
        • 不设置默认es3,配置文件默认es5,其他可选 es2015/es2016/es2017/...
      • module
        • 模块化标准
        • 默认commonjs、其他可选 amd/umd/es2015/es2020/...
      • sourceMap
        • 源代码映射,生成sourceMap,便于代码调试
      • outDir
        • 指定编译结果输出目录
        • 可以配置dist
      • lib
        • 指定标ts准库(ES对应版本内置对象的声明文件),接收一个数组
  • rootDir
    + 指定代码根目录
    + 可以配置src
    + strict
    + 开启严格模式

    • 使用 yarn tsc 直接运行
  • 原始类型

    • string
      • const a: string = 'hello'
      • 非严格模式可以是null或undefined
    • number
      • const b: number = 123
      • 包含 NaN Infinity
      • 非严格模式可以是null或undefined
    • boolean
      • const c: boolean = true
      • 非严格模式可以是null或undefined
    • void
      • const d: void = undefined
      • 标记函数返回类型
      • 非严格模式可以是null
    • null
      • const e: null = null
    • undefined
      • const f: undefined = undefined
    • symbol
      • const g: symbol = Symbol()
      • 需要配置target: es2015以上,或者配置lib引入es2015标准库
  • 强制使用中文显示错误消息

    • yarn tsc --locale zh-CN
    • 修改VSCode setting中相关的配置
    • 建议还是使用英文方式显示,便于问题查询定位
  • 作用域问题

    • 全局作用域下同名变量不能重复定义,可以放到函数作用域中,或者添加export {} 放到模块作用域下
  • Object类型

    • const foo: object = {} // [] // function() {} 可以接受数组、函数、对象
    • const obj: { name: string, value: number} = { name: 'hello', value: 123}
      • 强制对象类型的声明,可以使用对象字面量 {} 的方式,同时可以限制允许出现的属性
      • 使用接口定义更合适
  • 数组类型

    • const array: Array<number> = [1, 2, 3]
    • const array: number[] = [1, 2, 3]
  • 元组类型

    • 元组是一种明确元素数量和类型的特殊数组
    • const tuple: [number, string] = [123, '456']
    • 可以用来在一个函数中返回多个返回值
  • 枚举类型

    • enum关键字定义枚举类型

      enum Status {
          valid = 0,
          invalid
      }
      
    • 枚举值使用等号=赋值

    • 如果不指定枚举值,则默认从0开始,依次递增

    • 如果指定枚举值为数字,则默认依次递增

    • 如果指定一个枚举值为字符串,则需要指定所有它之后的所有枚举的初始的值

    • 枚举类型会被编译为双向键值对对象,可以使用key获得value,也可以使用value获得key

      var Status;
      (function (Status) {
          Status[Status["valid"] = 0] = "valid";
          Status[Status["invalid"] = 1] = "invalid";
      })(Status || (Status = {}));
      
    • enum关键字前增加const时为常量枚举,常量枚举不可以使用枚举值访问枚举的key

  • 函数类型

    • 函数声明形式

      function say (name: string, value: number, ...rest: number[]) : string {
          return `hello ${name}`
      }
      
    • 函数表达式形式

      const said: (name: string, value: number, ...rest: number[]) => string = (name: string, value: number, ...rest: number[]): string => {
          return `hello ${name}`
      }
      

      函数表达式将函数赋值给一个变量,需要给变量一个函数类型,使用箭头函数的形式

  • 任意类型

    • any类型
      • 不会进行类型检查
      • 用来兼容JS老代码
      • 存在类型安全问题
  • 隐式类型推断

    • 由typescript自行推断变量的类型
    • 建议给每个变量添加明确的类型
  • 类型断言

    • 当typescript无法明确推断变量的类型时,可以使用as关键字告诉typescript变量是什么类型
    • 也可以使用 <number> 尖括号<类型>的方式,但跟jsx混合使用的时候,会跟html标签混淆,建议使用as
  • 接口

    • 使用interface关键字定义接口,用来约束对象的结构

      interface Post {
          name: string
          value: number
          desc?: string
          readonly url: string   
      }
      
    • 属性名后加问号,表示可选属性,可选属性外的其他属性必须存在

    • 属性名前加readonly关键字,表示只读属性,初始化后不可修改

    • 不能包含接口定义外的其他属性

  • 面向对象编程中的概念,用来描述具体对象的抽象成员

    ES6以前,使用构造函数+原型的方式实现面向对象的类与继承

    ES6以后,提供了标准化的class来定义类

    typescript增强了class的相关语法(访问修饰符、抽象类等)

    • 基本使用

      • class关键字定一个一个类

      • 在类中声明属性,并初始化(定义时赋值,或在构造函数constructor中初始化)

        class Person {
            name: string
            age: number = 18
            constructor(name: string, age: number) {
                this.name = name
            }
        }
        
    • 访问修饰符

      控制类中属性和方法的访问级别

      • public: 默认
      • private: 无法被类的实例访问
        • 如果constructor被private修饰,将不能使用new实例化
      • protected: 无法被类的实例访问,可以在子类中访问
    • 只读属性

      • readonly关键字修饰类的属性
      • 只能在定义或者构造函数中初始化,之后不能被修改
    • 类与接口

      • 同样使用interface定义接口

      • 在interface中定义类的方法,但不提供实现

      • class使用implements关键字实现一个或多个接口,必须包含接口中定义的方法的实现

        interface Eat {
            eat(food: string): void
        }
        interface Run {
            run(speed: number): void
        }
        class Dog implements Eat, Run {
            eat(food: string) {
                console.log(food)
            }
            run(speed: number) {
                console.log(speed)
            }
        }
        
    • 抽象类

      • 使用abstract关键字定义抽象类

        • 抽象类不能被new实例化,只能被继承
      • 使用abstract关键字定义抽象类的抽象方法

        • 抽象方法不能具有实现
        • 子类继承后必须实现抽象方法
        abstract class Animal {
            eat(food: string): void {
                console.log(food)
            }
            abstract run(speed: number): void
        }
        
        class Cat extends Animal {
            run(speed: number): void {
        
            }
        }
        const cat = new Cat()
        cat.eat('food')
        
    • 泛型

      • 函数定义后使用<T>定义泛型,参数的类型可以被指定为T

      • 函数使用时在函数名后使用<类型>指明具体的类型,以此使函数在使用时可以传入不同类型的参数

        function hey<T>(value: T) {
            console.log(value)
        }
        hey<string>('123')
        hey<number>(123)
        
    • 类型声明

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