后续//

概述

编译器

过程

  • Typescirpt源码 -> TS AST
  • 类型检查器检查AST
  • TS AST->js源码
  • js源码->js AST
  • AST->字节码
  • 运行时计算字节码

    工具

  • TSC 操作上面前三个步骤

  • 后三步由浏览器 NodeJS 或其他的js引擎中的js运行时操作

    类型系统

    分类

  • 显示声明

  • 自动推导

    TS VS JS

  • 类型绑定

    • js动态,运行时才知道类型
    • ts是静态,在编译前能捕获部分错误
  • 是否自动类型转换
    • js 会
    • ts 多数不会
  • 何时检查类型
    • js不在乎使用类型,会尽所能把你提供类型转换成预期类型
    • ts在编译时做类型检查,会做静态分析
  • 何时报告错误

    • js在运行时抛出异常或执行隐式转换,
    • ts在编译时报告句法或语法错误//实际在编辑输入代码后立刻就有反馈

      代码编辑器设置

  • tsc

  • tslint
  • @types/node

    tsconfig.json

  • tsc —init 可以生产tsconfig.json

    tslint.json

  • tslint —init 可以生成

    index.ts

    编译

    运行

    类型全解

    any

  • unknown的子类型

  • 如果想用any,最好使用显示注解,
  • noImplicitAny 和strict启用都可针对隐式any类型报错

    unknown

  • 必须显示注解

  • 可以比较
  • 不会推导unknown类型为某种特定类型必须先证明一个值是某种类型

    1. let a: unknown = 30
    2. if(typeof a === 'number'){
    3. let d = a+10
    4. }

    类型字面量

  • 表示一个值的类型

    const

  • 常量

  • const c = true //这里推导出的c就是 一个true类型“类型字面量”

    boolean

  • any的子类

  • 两个值,true false

    number

  • 整数,浮点,正负数,Infinity,NaN

    bigint

  • 新引入

  • 处理较大整数时不用担心舍入误差
  • let a = 123n // 后面跟一个n

    string

    symbol

  • 新建一个符号,不与其他任何符号相等,即使用相同名称创建一个也是这样

  • unique symbol 一定是const的,不能用let

    对象

    结构化类型

  • 一种编程设计风格,只关心对象有哪些属性,不管属性使用什么名称,鸭子类型

    对象字面量句法

    1. let a:{b:number} = {
    2. b: 12
    3. }

    属性可选

    1. let a:{
    2. b:number
    3. c?:string
    4. [key: number]: boolean // 任意多个数字属性
    5. }
    6. //a={b:1,10:true}

    属性只读

  • readonly

    声明对象的四种方式

  • 字面量表示法

  • 空对象字面量表示
  • object类型
  • Object类型

    类型别名,并集,交集

    别名

    1. type Age = number
    2. type Person = {
    3. name: string
    4. age: Age
    5. }

    交集并集

    1. type Cat = {name:string,purrs:boolean}
    2. type Dog = {name:string,barks:boolean,wags:boolean}
    3. type CatOrDog = Cat | Dog
    4. type CatAndDog = Cat & Dog

    数组,元组,只读数组

    数组 Array

    1. function buildArray(){
    2. let a = []
    3. a.push(1)
    4. a.push('x')
    5. return a
    6. }
    7. let myArray = buildArray()
    8. myArray.push(true) //这里会报错,当数组离开定义时所在的作用域后确定类型不在扩张

    元组 Tupe

  • 数组子类型,定义数组的一种特殊方式

  • 声明时必须显示注解类型
  • 长度固定,各索引位上的值具有固定已知类型
  • 所以比数组安全 ```typescript let trainFares:[numbers,number?][]=[ [3.75], [8.23,7.7] ]

let list:[number,boolean, …string[]] = [1,false,’a’,’b’]

  1. <a name="QOQBJ"></a>
  2. #### 只读数组
  3. ```typescript
  4. type A = readonly string[]
  5. type B = ReadonlyArray<string>
  6. type C = Readonly<string[]>

null undefined,void never

  • null是缺少值
  • undefined是尚未赋值的变量
  • void 是函数没有显示返回任何值
  • never是函数不返回(抛出异常,永远运行下去)
  • unknown是其他每个类型的父类型,never是其他每个类的子类型

枚举

  1. const enum Language{
  2. English,
  3. Spanish,
  4. Russian
  5. }
  6. //
  • 枚举不安全,
  • 如果坚持使用,可以制定一些TSLint规则,如发现数值枚举,和非const枚举发出提醒

    函数

    声明函数和调用函数

    5种函数什么方式

    ```typescript //具名函数 function gree(name: string){ return ‘hello ‘+ name } //函数表达式 let greet2 = function(name: string){ return ‘hello ‘+ name

} //箭头函数表达式 let greet3 =(name: string) => { return ‘hello ‘+ name } //箭头函数简写 let greet4 =(name: string) => return ‘hello ‘+ name //函数构造法

let greet5 = new Function(‘name’,’return “hello “ + name’)

  1. <a name="Dw11W"></a>
  2. #### 可选参数和默认参数
  3. ```typescript
  4. function log(message:string,userId?: string){
  5. //...
  6. }
  7. function log(message:string,userId='not signed in'){
  8. //...
  9. }

剩余参数

  • 数组实现
  • arguments实现//不安全 类型是any
  • 使用 …

    函数的其他调用方式

  • call

  • apply
  • bind

    注解this类型

  • this的值取决于调用方式,

  • 可以指定this ,防止这种混淆 ```typescript function fancyDate(this:Date){ return ${this.getDate()}/${this.getMonth()}/${this.getFullYear()} }
  1. <a name="n7xbx"></a>
  2. #### 生成器函数
  3. - 生成一系列值的便利方式
  4. - 惰性的
  5. ```typescript
  6. function* createFibonaciiGenerator(){
  7. let a = 0
  8. let b = 1
  9. while(true){
  10. yield a; //调用next 把这个给调用方,然后停止执行
  11. [a,b] = [b,a+b]
  12. }
  13. }
  14. // 显示注解生成器
  15. function* createNumbers(): IterableIterator<number>{
  16. //....
  17. }

迭代器

  • 可迭代对象
    • 有Symbol.iterator的属性对象,该属性的值为一个函数,返回迭代器
  • 迭代器
    • 有next方法的对象,该方法返回一个具有 value 和done属性的对象 ```typescript let numbers = { *Symbol.iterator{ for(let n=1;n<10;n++){ yield n } } }

// 使用 for-of 迭代一个迭代器 for(let a of numbers){ //1,2,3 etc } //展开一个迭代器 let allNumbers = [… numbers] //析构 一个迭代器 let [one,two, …rest] = numbers

  1. <a name="tO5Ce"></a>
  2. #### 调用签名
  3. - 表示 函数类型的句法,也称调用签名
  4. - 无法表示默认值
  5. ```typescript
  6. (a:number,b:number) => number
  7. type Log = (message: string, userId?: string) => void
  8. let log: Log = (
  9. message,
  10. userId = 'not signed in'
  11. ) => {
  12. let time = new Date().toISOString()
  13. console.log(time,message,userId)
  14. }

上下文类型推导

  • 行内声明,无需显式注解函数类型 ```velocity function times( f:(index: number)=>void, n:number ){…}

times(n=>console.log(n),4) //可以

function f(n){…} times(f,4) //不可以

  1. <a name="onlSm"></a>
  2. #### 函数类型重载
  3. - 使用完整型调用签名,声明多个
  4. - 自己动手组合多个签名实现声明的签名
  5. ```javascript
  6. type Reserve = {
  7. (from:Date,to:Date, destination: string):Reservation
  8. (from:Date,destination:String):Reservation
  9. }
  10. let reserve: Reserve=(
  11. from:Date,
  12. toOrDestination:Date|string,
  13. destination?:string
  14. ) => {
  15. //...
  16. if(toOrDestination instanceof Date&&destination !== undefined){
  17. //...
  18. }else if(typeof toOrdestination === 'string'){
  19. }
  20. }

多态

泛型参数

  1. type Filter = {
  2. <T>(array:T[],f:(item: T)) => boolean):T[]
  3. }
  4. let filter:Filter = (array,f) => //...
  5. type Filter<T> = {
  6. (array:T[],f:(item: T)) => boolean):T[]
  7. }
  8. let filter:Filter<number> = (array,f) => //...
  9. type Filter = <T>(array:T[],f:(item: T)) => boolean) => T[]
  10. let filter:Filter = //...
  11. type Filter<T> = (array:T[],f:(item: T)) => boolean) => T[]
  12. let filter:Filter = //...
  13. fuction filter<T>(array:T[],f:(item: T)) => boolean):T[]{...
  14. }

自动推导与显示注解

泛型别名

  1. type MyEvent<T> = {
  2. target: T
  3. type: string
  4. }
  5. function triggerEvent<T>(event: MyEvent<T>):void{
  6. //...
  7. }
  8. triggerEvent({//T是 Element|null
  9. target:document.querySelector('#myButton'),
  10. type:'mouseover'
  11. })

受限的多态

  1. function mapNode<T extends TreeNode>(
  2. node: T,
  3. f:(value: string)=>string
  4. ):T{
  5. return{
  6. ...node,
  7. value:f(node.value)
  8. }
  9. }
  10. /// 多个约束
  11. type HasSides = {numberOfSides: number}
  12. type SidesHaveLength = {sideLength: number}
  13. function logPerimeter<Shape entends HasSides & SidesHaveLength>(s: Shape){
  14. console.log(s.numberOfSides*s.sideLength)
  15. return s
  16. }
  17. // 模拟变长参数
  18. function call<T extends unknown[],R>(
  19. f:(...args:T)=>R,
  20. ...args:T
  21. ):R{
  22. return f(...args)
  23. }

泛型默认类型

  1. type MyEvent<T = HTMLELement> = {
  2. target: T
  3. type: string
  4. }

类型驱动开发

  • 先规划类型,再填充细节

    类和接口

    类和继承

  • class extends

  • abstract
  • private protected public
  • readonly 属性 ```typescript class Postion{ constructor( private file: File, //自动赋值给 this.file 并设置为私有 private rank: Rank
    ){} } abstract class Piece{ //不能new protected position: Position constructor( private readonly color:Color, //自动赋值,并设为私有 file:File, rank:Rank ){ this.position = new Position(file,rank) } abstract canMoveTo(position: Position):boolean //子类必须实现

}

class King extends Piece{ canMoveTo(postion:Position){ //… } }

  1. <a name="PwY0d"></a>
  2. #### super
  3. - 方法调用 super.take
  4. - 构造方法调用 super()
  5. - 只能访问父方法,不能访问父属性
  6. <a name="Rq8Bi"></a>
  7. ### 以this为返回类型
  8. ```typescript
  9. let set = new Set
  10. set.add(1).add(2)
  11. class Set{
  12. add(value:number):Set{ //这里的Set 改为 this,下面子类的实现就可以删除
  13. //...
  14. }
  15. }
  16. class MutableSet extends Set{
  17. add(value:number):MutableSet{
  18. //...
  19. }
  20. }

接口

  • 类经常当做接口使用
  • 与类型别名相似,接口是一种命名类型的方式 ```typescript type Food = { calories: number tasty:boolean } type Sushi = Food&{ salty: boolean }

interface Food { calories: number tasty:boolean }

interface Sushi extends Food{ salty: boolean } ```

与别名的区别

  • 别名更为通用,右边可以是任何类型,包括类型表达式
  • 扩展接口时,会检查扩展接口是不是可以赋值给被扩展的接口
  • 同名接口自动合并,同名类型别名将导致编译错误

    声明合并

  • 合并的接口声明方式的方式必须一样

    实现

  • implements

  • 可以声明属性,不能使用可见性修饰符,不能用static,可以用readonly

    实现接口还是扩展抽象类

    类是结构化类型

  • 两个不用名称的类,实现了同样的方法或有同样的属性,可以替换使用

  • 有private 或 protect 时,情况就不一样了

    类既声明值也声明类型

    多态

    混入

    装饰器

  • 实验特性,需要在tsconfig中开启

    模拟final类


  • 类型进阶

处理错误

异步编程,并发并行

前后端框架

命名空间和模块

与javascirpt 互操作

构建和运行