深入浅出TypeTypeScript
为什么要学TypeScript?
TS在社区的活跃度越来越高

TypeScript vs JavaScript
 TS的优势:
 TS的优势:
- 
类型化思维方式,使开发更严谨,提前发现错误,减少改Bug时间 
- 
类型系统提高了代码可读性,维护和重构代码更加容易 
- 
补充了接口、枚举等开发大型应用时JS缺失的功能 
TS带来了什么?
- 类型安全
- 下一代JS特性
- 完善的工具链
TS不仅仅是一门语言,更是生产力工具
TS推荐
- Awesome TypeScript:TS开源教程及应用
- Byte Tech:TS&React:React + TypeScript开发模式介绍
- Typescript Playground:TS到JS在线编译
TS基础
基础类型
- boolean、number、string
- 枚举enum
- any、unknown、void
- never
- 数组类型[]
- 元祖类型tupte
函数类型
定义:TS定义函数类型时要定义输入参数类型和输出类型
输入参数:参数支持可选参数和默认参数
输出参数:输出可以自动推断,没有返回值时,默认为void类型
函数重载:名称相同但参数不同,可以通过重载支持多种类型
pickCard方法根据传入参数的不同会返回两种不同的类型。 如果传入的是代表纸牌的对象,函数作用是从中抓一张牌。 如果用户想抓牌,我们告诉他抓到了什么牌。 但是这怎么在类型系统里表示呢。 方法是为同一个函数提供多个函数类型定义来进行函数重载。 编译器会根据这个列表去处理函数的调用。 重载pickCard函数:
            
            
              typescript
              
              
            
          
          let suits = ["hearts", "spades", "clubs", "diamonds"]; 
function pickCard(x: {suit: string; card: number; }[]): number;
function pickCard(x: number): {suit: string; card: number; }; 
function pickCard(x): any { 
// Check to see if we're working with an object/array 
// if so, they gave us the deck and we'll pick the card 
if (typeof x == "object") {
let pickedCard = Math.floor(Math.random() * x.length); 
return pickedCard; 
} 
// Otherwise just let them pick the card 
else if (typeof x == "number") { 
let pickedSuit = Math.floor(x / 13); 
return { suit: suits[pickedSuit], card: x % 13 };
 } 
} 
let myDeck = [{ suit: "diamonds", card: 2 }, { suit: "spades", card: 10 }, { suit: "hearts", card: 4 }]; 
let pickedCard1 = myDeck[pickCard(myDeck)];
alert("card: " + pickedCard1.card + " of " + pickedCard1.suit); 
let pickedCard2 = pickCard(15); 
alert("card: " + pickedCard2.card + " of " + pickedCard2.suit);为了让编译器能够选择正确的检查类型,它与JavaScript里的处理流程相似。 它查找重载列表,尝试使用第一个重载定义。 如果匹配的话就使用这个。 因此,在定义重载的时候,一定要把最精确的定义放在最前面。
interface
定义:接口是为了定义对象类型
特点:
- 可选属性:?
接口里的属性不全都是必需的。 有些是只在某些条件下存在,或者根本不存在。带有可选属性的接口与普通的接口定义差不多,只是在可选属性名字定义的后面加一个?符号。
可选属性在应用"option bags"模式时很常用,即给函数传入的参数对象中只有部分属性赋值了。下面是应用了"option bags"的例子:
            
            
              typescript
              
              
            
          
          interface SquareConfig {
    color?: string; 
    width?: number; 
} 
function createSquare(config: SquareConfig): {color: string; area: number} { 
  let newSquare = {color: "white", area: 100}; 
  if (config.color) { 
     newSquare.color = config.color; 
     } 
     if (config.width) { 
       newSquare.area = config.width * config.width; 
       } 
       return newSquare; 
} 
let mySquare = createSquare({color: "black"});- 只读属性:readonly
一些对象属性只能在对象刚刚创建的时候修改其值。
            
            
              typescript
              
              
            
          
          interface Point {
   readonly x: number; 
   readonly y: number; 
}- 可以描述函数类型
- 可以描述自定义属性
总结:接口非常灵活duck typing
类
定义:写法和JS差不多,增加了一些定义
特点: 增加了public、private、protected修饰符 抽象类:
- 只能被继承,不能被实例化
在TypeScript里,我们可以使用常用的面向对象模式。当然,基于类的程序设计中最基本的模式是允许使用继承来扩展现有的类。
            
            
              typescript
              
              
            
          
          class Animal { 
    name:string; 
    constructor(theName: string) { this.name = theName; }      
    move (distanceInMeters: number = 0) { 
         console.log(`${this.name} moved ${distanceInMeters}m.`); 
         } 
} 
class Snake extends Animal { 
    constructor(name: string) { super(name); } 
    move(distanceInMeters = 5) { 
        console.log("Slithering..."); 
        super.move(distanceInMeters); 
     } 
} 
class Horse extends Animal { 
    constructor(name: string) { super(name); } 
    move(distanceInMeters = 45) { 
        console.log("Galloping..."); 
        super.move(distanceInMeters); 
    } 
} 
let sam = new Snake("Sammy the Python"); 
let tom: Animal = new Horse("Tommy the Palomino"); 
sam.move(); 
tom.move(34);- 作为基类,抽象方法必须被子类实现
- interface约束类,使用implements关键字
TS进阶
高级类型
- 联合类型 |
- 交叉类型 &
- 类型断言
- 类型别名(type VS interface) 定义:给类型起个别名
相同点:
- 都可以定义对象或函数
- 都允许继承
差异点:
- interface是TS用来定义对象,type是用来定义别名方便使用;
- type可以定义基本类型,interface不行
- interface可以合并重复声明,type不行
泛型-什么时候需要泛型
官方定义: 软件工程中,我们不仅要创建一致的定义良好的API,同时也要考虑可重用性。 组件不仅能够支持当前的数据类型,同时也能支持未来的数据类型,这在创建大型系统时为你提供了十分灵活的功能。
在像C#和Java这样的语言中,可以使用泛型来创建可重用的组件,一个组件可以支持多种类型的数据。 这样用户就可以以自己的数据类型来使用组件。
应用场景: 定义一个print函数,这个函数功能是把传入的参数打印出来,再返回这个参数,传入参数的类型是string,函数返回类型为string
基本使用
基本定义: 泛型的语法是<>里面写类型参数,一般用T表示; 例子:identity函数。 这个函数会返回任何传入它的值。 你可以把这个函数当成是echo命令。
不用泛型的话,这个函数可能是下面这样:
            
            
              typescript
              
              
            
          
          function identity(arg: number): number {
    return arg;
}因此,我们需要一种方法使返回值的类型与传入参数的类型是相同的。 这里,我们使用了 类型变量,它是一种特殊的变量,只用于表示类型而不是值。
            
            
              typescript
              
              
            
          
          function identity<T>(arg: T): T {
    return arg;
}使用时有两种方法指定类型:
- 定义要使用的类型
- 通过TS类型推断,自动推导类型
- 泛型的作用是临时占位,之后通过传来的类型进行推导
基础操作符
- typeof:获取类型
- keyof:获取所有键
- in:遍历枚举类型
- T[K]:索引访问
- extends:泛型约束
常用工作类型
- Partial:将类型属性变为可选
- Required:将类型属性变为必选
- Readonly:将类型属性变为只读
- Pick、Record......
TypeScript实战
声明文件
- 
declare:三方库需要类型声明文件 
- 
.d.ts:声明文件定义 
- 
@types:三方库TS类型包 
- 
tsconfig.json:定义TS的配置 如果一个目录下存在一个 tsconfig.json文件,那么它意味着这个目录是TypeScript项目的根目录。tsconfig.json文件中指定了用来编译这个项目的根文件和编译选项。tsconfig.json示例文件:
- 
使用 "files"属性
            
            
              typescript
              
              
            
          
              {
    "compilerOptions": {
        "module": "commonjs",
        "noImplicitAny": true,
        "removeComments": true,
        "preserveConstEnums": true,
        "outFile": "../../built/local/tsc.js",
        "sourceMap": true
    },
    "files": [
        "core.ts",
        "sys.ts",
        "types.ts",
        "scanner.ts",
        "parser.ts",
        "utilities.ts",
        "binder.ts",
        "checker.ts",
        "emitter.ts",
        "program.ts",
        "commandLineParser.ts",
        "tsc.ts",
        "diagnosticInformationMap.generated.ts"
    ]
}泛型约束后端口类型
泛型约束后端口类型可以是任何类型,只要满足特定的约束条件。在泛型中,可以使用接口、类或其他泛型类型作为约束条件。
例如,假设有一个泛型函数,用于判断两个对象是否相等:
            
            
              typescript
              
              
            
          
          Copyfunction isEqual<T>(a: T, b: T): boolean {
  return a === b;
}如果要对泛型进行约束,可以使用接口来定义约束条件。例如,可以定义一个接口 Comparable,表示具有比较相等性的类型:
            
            
              typescript
              
              
            
          
          Copyinterface Comparable {
  equals(other: any): boolean;
}
function isEqual<T extends Comparable>(a: T, b: T): boolean {
  return a.equals(b);
}在这个例子中,isEqual 函数的泛型参数 T 被约束为实现了 Comparable 接口的类型。这样,只有实现了 equals 方法的类型才能被传递给 isEqual 函数。