拉勾教育学习第二周——TypeScript

92 阅读7分钟

语言类型

按照类型安全区分

强类型语言和弱类型语言

按照类型检查区分

静态类型语言和动态类型语言

强类型和弱类型

强类型语法上不允许任意的隐式类型转换,弱类型允许

弱类型语言的问题:
  1. 类型异常需要等到程序运行才会被发现
const obj = {};
obj.fn();
  1. 函数功能改变
const sum = (a, b) => a + b;
sum(1, '1');
  1. 对象的键
const obj = {};
obj[true] = 1; // 键实际上是'true'
强类型语言的优势:
  1. 错误更早暴露
  2. 代码更智能,编码更准确(编辑器会时时刻刻提示类型)
  3. 重构更牢靠
  4. 减少不必要的类型判断(不再需要用typeof判断)

静态类型和动态类型

静态类型

变量声明时类型是明确的,声明之后不能再修改

动态类型

运行阶段才能够明确变量类型,且可以随时改变

Flow

js的类型检查器

使用步骤:

  1. 命令行:yarn add flow-bin 安装
  2. 第一行写 //@flow
  3. 关掉vscode设置里的JavaScript › Validate: Enable 禁用js验证
  4. 命令行:yarn flow init 初始化.flowconfig文件
  5. 命令行:yarn flow 执行命令
  6. 命令行:yarn flow stop 结束服务

编码结束后移除类型注解的两种方法:

  1. flow-remove-types 安装 yarn add flow-remove-types 运行 yarn flow-remove-types . -d dist (.表示本文件,可以写src)
  2. babel/preset-flow

开发工具插件: vscode的flow language support 保存代码后才会检测出类型错误

类型注解

  1. 函数参数 function sum (a: number, b: number) { return a + b }
  2. 变量 let num: number = 100
  3. 函数返回值 function fn (): void {} // ovid表示无返回值

各种类型的写法

  1. 基本类型: string、number(包括NaN和Infinity)、boolean、null(值只能是null)、void(表示undefiened)、symbol (用 | 隔开表示或)

  2. 数组: Array、number[](两种均全部由数字组成的数组)

[string, number](长度为2,第一项为字符串,第二项为数字的数组)(明确元素数量及所有元素类型的数组叫元组)

  1. 对象: {foo: string, bar: number}(有值为字符串的foo属性和值为数字的bar属性的对象)

{foo: string, bar?: number}(同上,但是bar可选)

{[string]: string}(运行添加任意个数的属性,但是属性和值必须都是字符串)

  1. 函数: (string, number) => void(两个参数,第一个是字符串,第二个是数字,且没有返回值的函数)

  2. 特殊类型: 'foo'(只能为'foo') 'success' | 'warning' | 'danger'(只能为三个值之一)

  3. type关键词声明类型 type stringOrNumber = string | number stringOrNumber可以作类型用

  4. maybe类型

  5. mixed(任一类型,但仍然是强类型,如果有使用隐患的话就会报错,要用typeof进行类型判断) any(任一类型,弱类型)

flow.org/en/docs/typ… www.saltycrane.com/cheat-sheet…

  1. 浏览器api 获取页面元素时的类型:HTMLElement | null

TypeScript

Javascript的超集(superset)

优点:
  1. 任何一种js运行环境都支持
  2. 功能比flow强大,生态更完善
缺点:
  1. 语言本身多了很多概念
  2. 项目初期,代码编写的成本增加
命令:

tsc(TypeScript compile)

yarn tsc '文件路径' 可以把特定的ts文件编译为js文件

yarn tsc 不写路径,则编译tsconfig.json里rootDir目录下的所有ts文件

yarn tsc --locale zh-CN 打印的中文的错误

在vscode的设置中查typescript locale可以设置中文错误提示

yarn tsc --init 命令生成ts的配置文件tsconfig.json

tsconfig.json选项:

target 编译后的js文件采用的es标准,默认es5

module 输出后的代码选择的模块化,默认commonjs

lib 额外的标准库文档,可添加,默认[](一旦添加了新的标准库,会覆盖原有的,要加回"DOM")

标准库就是内置对象所对应的声明

sourceMap 是否开启源代码映射,默认true(scourceMap文件调试源代码?)

outDir 编译结果输出到的文件夹,默认"./"

rootDir 源代码的目录,默认"./"

strict 是否开启严格模式,默认true(函数参数必须有类型,不能是any)

strictNullChecks 是否允许已设置类型的变量,设置为null

。。。。。。

类型注解(大多数与flow相同)

  1. 非严格模式下,已设定类型的变量,可以为null (可以单独设置strictNullChecks)

  2. ts的标准库是es5,因此编译es6新增的symbol会报错,任何es6新增的对象都会报错 解决:把配置文件里的target改为es2015,或者在lib里加上"es2015"

  3. object类型可以泛指所有的复杂数据类型,对象字面量的写法单指对象

  4. 冒号前加?,意为可选成员

  5. 不同文件的全局作用域有同名的变量会报错,需要分别放入单独的作用域中

枚举类型

enum关键字

enum Status {
    pending = 1,
    success = 2,
    fail = 3
}
// 值都是连续数字的话,可以缩写为
enum Status {
    pending = 1, // 值是从0开始的话可以。第一个也可以不写值
    success, // 依次累加
    fail
}

// 使用
const obj = {
    status: Status.pending
}

// 可以用索引的方法获取枚举类型的值
Status[0]
// 如果不需要用索引的方法获取枚举类型的值,最好将枚举类型设置为常量
const enum Status {
    pending = 1,
    success = 2,
    fail = 3
}

接口

约定对象有那些成员和各自的类型,interface关键字

interface Person {
  name: string;  // 用分号隔开
  age: number;
  readonly gender: boolean; // readonly关键字 只读,初始化后就不能修改
  nickname?: string;
}
const bob: Person = {
  name: 'bob',
  age: 18,
  gender: true
}


interface Standard {
    [prop: string]: string // prop词可以用其他词替换
}
// 对象可以有任意属性,但是键值必须都是字符串

类里的写法

class Person {
  name: string // 类的属性使用前必须声明类型
  age: number
  constructor (name: string, age: number) {
    this.name = name;
    this.age = age;
  }
}

类的访问修饰符

class Person {
  public name: string
  private age: number
  protected gender: boolean
  constructor (name: string, age: number) {
    this.name = name;
    this.age = age;
  }
  sayAge () {
      console.log(this.age); // 私有属性只能在内部使用
  }
}

class Child extends Person {
    constructor (name: string, age: number) {
        super(name, number);
        console.log(this.gender); // 受保护属性只能在子类内部使用
    }
}
public关键字

表示公有成员,不写也一样,推荐写

private关键字

表示私有成员,只能在内部访问

protected关键字

表示受保护的成员,只能在类内部和子类内部访问

类的只读属性

关键字readonly,写在访问修饰符后面

只能在初始化或者构造函数里赋值,之后就不能再改

类的构造函数加private关键字,则类不能在外部生成实例,可以用静态方法在类的内部创建实例

class Person {
  public name: string
  private age: number
  private constructor (name: string, age: number) {
    this.name = name;
    this.age = age
  }
  static create (name: string, age: number) {
    return new Person(name, age);
  }
}
const bob = Person.create('bob', 20);

类与接口

约束一个类 interface和inplements关键字

interface run {
  run (distance: string): void
}
interface eatAndDrink { // 一个接口最好只约束一个属性
  eat (food: string): void
  drink (wine: string): void
}
class Person implements run, eatAndDrink { // implements后面可以跟多个接口
  run (distance: string): void {
    console.log(`run ${distance}`);
  }
  eat (food: string): void {
    console.log(`eat ${food}`);
  }
  drink (wine: string): void {
    console.log(`eat ${wine}`);
  }
}

抽象类

与接口的区别,抽象类里的方法有方法体 abstract关键字

abstract class Animal {
  eat (food: string) {
    console.log(`eat ${food}`);
  }
  abstract run (distance: number): void
  // 抽象类里的抽象方法不用写方法体
}
class Dog extends Animal { // 继承了抽象类里的方法eat
    // 父类里有抽象方法,字类必须实现
    // 可以用vscode的代码修正功能:点击字类名称,ctrl + .
  run(distance: number): void {
    console.log(`run ${distance}`);
  }
}

泛型

function creatNumberArray (length: number, value: number): number[] {
  return Array<number>(length).fill(value);
}
function creatStringArray (length: number, value: string): string[] {
  return Array<string>(length).fill(value);
}

// 用泛型改进,T是泛型参数
function createArray<T> (length: number, value: T): T[] {
  return Array<T>(length).fill(value);
}

类型声明

在ts文件里引入js库,如果该js库自带的类型声明模块,就需要根据vscode提示下载类型声明模块 否则需要手写类型声明 declare关键字

declare function fn (params: number): string;