阅读 510

TypeScript使用指南(初级篇)

安装编译工具

npm install typescript -g

基本命令

  • npx tsc --init : 初始化配置文件 tsconfig.json
  • npx tsc -w : 监听文件变化,实时编译

基本类型

类型

  • boolean: 布尔值
  • number: 数字,可以是整数、浮点数、各种进制
  • string: 字符串
  • Array<number>: 数组,尖括号内为数组元素的类型
  • [string, number]: 元组,有限长度的数组,可以指定每一个元素的类型
  • enum: 枚举,默认从0开始
  • unknown: 未知类型,可以是任意值,但依然会被类型检测
  • any: 任意类型,可以是任意值,编译期间不做类型检测
  • void: 空值,一般用作无返回的函数
  • null: null值,一般不使用
  • undefined: undefined值,一般用作函数默认参数的占位符
  • never: never类型,有2种情况:无法执行到最后的函数(异常,死循环),返回never的函数,常用于类型收窄(全面类型检查)
  • object: 对象类型

类型断言

as关键词: someValue(某变量) as string(某类型),当你比编译器了解的更多的时候,可以用类型断言来辅助编译器

类型大小写的问题

在ts中,都使用小写(number, string, boolean, symbol, object),大写是js中的原语类型(Number, String, Boolean, Symbol, Object),在ts中不应该被使用

接口

接口类型

  • 对象:指定对象属性的类型
  • 函数:指定函数参数和返回值的类型
  • 索引:指定索引的类型,比如number,string。如果是string,则索引既可以是string,也可以是number。如果是number,则索引只能是number
  • 类:指定类的构造函数、实例属性和方法,定义一个类必须同时定义2个接口,一个是构造函数的,一个是实例属性和方法的
  • 混合:指的是即是函数也是对象的一种类型,可以像函数一样调用,可有自己的属性和方法

属性类型

  • 可选属性:用问号,例:color?: string
  • 只读属性:用readonly关键词,例:readonly color: string

属性检查

编译器会对实现接口的函数调用,进行属性检查,如果传入参数直接是对象本身,会对接口定义之外的属性报错,有两种办法解决该问题

  • 使用as关键词做类型断言
  • 使用变量去承载该对象,传入变量到参数

:尽可能地不要使用接口定义之外的属性,实在不行,就用as关键词

继承

  • 接口继承接口:相当于直接copy所有的属性,可以同时继承多个
  • 接口继承类:同上copy所有属性,包括private和protected,但该接口的实现类必须是该类本身或者是该类的子类

函数

声明式函数

function myAdd (x: number, y: number): number {
  return x + y
}
复制代码

赋值式函数

let myAdd: (x: number, y:number) => number = function(x: number, y: number): number {
  return x + y
}
复制代码

类型推断

针对赋值式函数,可以省去一边的类型定义,因为编译器会根据另一边推断出具体类型

let myAdd = function(x: number, y: number): number {
  return x + y
}

let myAdd2: (x: number, y:number) => number = function(x, y) {
  return x + y
}
复制代码

参数类型

  • 可选参数:用问号,color?: string
  • 默认参数:用等号,color = '#000000'
    • 默认参数的字面量会让编译器推断出具体类型,所以无需再加上类型定义
    • 默认参数也是可选参数
  • 剩余参数:用...,(x: number, ...restOfNumber: Array<number>)

this参数

函数第一个参数如果是this,则是对this的类型约束,没有特定需要,一般不去设置this参数

重载

定义多个同名函数,最后一个函数为具体实现,前面的函数为参数声明

:ts的函数重载只是为了类型检测,与其他语言可能会有差异

字面量类型

  • 字符串
  • 数字
  • 布尔值

并集和交集类型

  • 并集:let pet = Fish | Bird
  • 交集:let dom = Dom & Event

继承

class Animal {
  move(x: number = 0) {
    console.log(`Animal moved ${x}m.`);
  }
}

class Dog extends Animal {
  bark() {
    console.log("Woof! Woof!");
  }
}

const dog = new Dog();
dog.bark();
dog.move(10);
dog.bark();
复制代码

修饰符

  • public: 都可使用
  • private:只有本类可以使用,子类和外部实例不允许使用,es6的私有属性也支持,如:#name: string
  • protected: 只有父类和子类的函数可以使用,外部实例不允许使用
  • readonly:只读属性,只有定义和构造函数可以给这些属性赋值

参数属性

构造函数的参数如果带有任意修饰符,则该属性默认属于实例属性

访问器

get和set模型

静态属性

属于类本身的属性,只能通过类名访问

接口类

不可被实例化,只能被继承

构造函数

用new关键字创建实例的时候,自动执行的初始化函数

枚举

数字型枚举

初始为数字的枚举类型,默认从0开始,可以指定为任意数字,如果未指定,则沿用上一个常量+1

字符串型枚举

不再拥有自动加一的特性,必须指定每一个枚举值

混合类型

同时拥有字符串和数字的混合类型,不建议使用

计算成员和常量成员

以下情况符合其一就是常量成员

  • 第一个成员没有初始值,默认是0
  • 没有初始值,且前一个成员为数字型常量
  • 字面量和部分数学符号组成的表达式,如:-1, '123'.length, 1 << 1等

联合枚举和枚举成员类型

  • 联合枚举:枚举类型拥有有限个成员,这些成员组成了类型的并集,在一些条件判断的时候,编译器可以去识别这些类型,如果条件为恒真或者恒假,则会提示错误,例:
enum E {
  Foo,
  Bar,
}

function f(x: E) {
  if (x !== E.Foo || x !== E.Bar) {
  // This condition will always return 'true' since the types 'E.Foo' and 'E.Bar' have no overlap.
    //
  }
}
复制代码
  • 枚举成员类型:针对枚举类型的常量成员,也是一种独立的类型,例:
enum ShapeKind {
  Circle,
  Square,
}

interface Circle {
  kind: ShapeKind.Circle;
  radius: number;
}

interface Square {
  kind: ShapeKind.Square;
  sideLength: number;
}

let c: Circle = {
  kind: ShapeKind.Square,
  // Type 'ShapeKind.Square' is not assignable to type 'ShapeKind.Circle'.
  radius: 100,
};
复制代码

枚举运行时

在运行时,枚举类型是真实存在的,可以打印出对应的值

枚举编译时

运行时,枚举类型虽然存在,但对应的key的字符串却可能跟你预期的不一样,编译时可以用 keyof typeof 关键词来获取key的联合类型,例:

enum LogLevel {
  ERROR,
  WARN,
  INFO,
  DEBUG,
}

/**
 * This is equivalent to:
 * type LogLevelStrings = 'ERROR' | 'WARN' | 'INFO' | 'DEBUG';
 */
type LogLevelStrings = keyof typeof LogLevel;
复制代码

反向映射

数字型枚举类型,可以根据数字获取到key的字符串,例:

enum Enum {
  A,
}

let a = Enum.A;
let nameOfA = Enum[a]; // "A"
复制代码

常量枚举

在枚举关键词之前使用 const 关键词,可以避免编译产生额外的代码和反向映射,项目中推荐使用

环境枚举

用来定义已存在的枚举类型,不会编译成代码,在枚举类型前使用 declare 关键词,例:

declare enum Enum {
  A = 1,
  B,
  C = 2,
}
复制代码

泛型

为了提高代码复用率,泛型可以允许指定类型参数,来创建逻辑相同的代码片段(类型,类,函数),例:

function identity<T>(arg: T): T {
  return arg;
}
let output = identity<string>("myString");
复制代码

泛型类型变量

上面的示例,arg的参数类型是不确定的,如果要使用数组类型的length属性,需要使用泛型数组类型,例:

function identity<T>(arg: Array<T>): Array<T> {
  console.log(arg.length)
  return arg;
}
复制代码

泛型类型

上面的示例,要利用泛型函数来创建一个新的函数,可以用以下代码:

let myIdentify: <T>(arg: T) => T = identify
复制代码

这里T只是一个标识符,也可以用其他任意字符替代

我们也可以用调用签名的方式去写(对象字面量类型):

let myIdentify: {<T>(arg: T): T} = identify
复制代码

初看之下可能比较复杂,但实际上就是一个对象的key,value的键值对,key表示输入,value表示输出

因此衍生出使用泛型接口来重写上面的代码,将调用签名抽离成一个函数类型的接口:

interface GenericIdentityFn {
  <T>(arg: T): T;
}

function identity<T>(arg: T): T {
  return arg;
}
let myIdentity: GenericIdentityFn = identity;
复制代码

然后可以将泛型参数转移到整个接口上,这样所有成员函数都可以使用这个泛型参数:

interface GenericIdentityFn<T> {
  (arg: T): T;
}

function identity<T>(arg: T): T {
  return arg;
}

let myIdentity: GenericIdentityFn<number> = identity;
复制代码

泛型接口的使用看具体业务情况

泛型类

就是在类的基础上扩展了泛型参数,唯一需要注意的是,静态成员无法使用泛型参数

class GenericNumber<T> {
  zeroValue: T;
  add: (x: T, y: T) => T;
}
let myGenericNumber = new GenericNumber<number>();
复制代码

泛型约束

泛型参数一般是类似any的存在,如果需要使用它的一些属性,比如length,则需要额外定义,可以使用Array,或者也可以使用继承的方式,创建一个接口,指定属性来约束泛型参数,例:

interface Lengthwise {
  length: number;
}

function loggingIdentity<T extends Lengthwise>(arg: T): T {
  console.log(arg.length); // Now we know it has a .length property, so no more error
  return arg;
}
复制代码

:这样一来,函数传参必然是一个包含length属性的对象,就不能是任意值了

泛型中使用类

当使用泛型在ts中创建工厂时,则有必要引用类的构造函数,例:

function create<T>(c: { new (): T }): T {
  return new c();
}
复制代码

以下是具体示例:

class BeeKeeper {
  hasMask: boolean;
}

class ZooKeeper {
  nametag: string;
}

class Animal {
  numLegs: number;
}

class Bee extends Animal {
  keeper: BeeKeeper;
}

class Lion extends Animal {
  keeper: ZooKeeper;
}

function createInstance<A extends Animal>(c: new () => A): A {
  return new c();
}

createInstance(Lion).keeper.nametag;
createInstance(Bee).keeper.hasMask;
复制代码

参考

www.typescriptlang.org/docs/handbo…

文章分类
前端
文章标签