头图

前言

TypeScript is JavaScript with syntax for types.

这是是官网对TypeScript的定义。作为JavaScript的超集,TypeScript重点提出了类型系统。如今 TS 已经受到了广泛的应用,它坚持与 JavaScript 核心语法标准 ECMAScript 同步发展,对于熟悉JavaScript的开发人员来说也是十分容易上手的。关于 TypeScript 的优缺点就不过多阐述了,下面进入正题

安装

TypeScript 的命令行工具全局安装方法:

npm install typescript -g

安装完成后,我们可以在任何地方通过执行命令tsc [tsfile]编译 typescript 文件

数据类型

TypeScript支持与JavaScript几乎相同的数据类型。类型声明语法如下:

let [variable]: [type]

JavaScript 中的数据类型包括:原始数据类型和引用类型。原始数据类型包括:boolean、number、string、null 和 undefined,以及ES6新增的Symbol和BitInt。

原始基本类型

下面是五种基本类型对应的声明写法:

类型示例/值
booleanlet b: boolean = true false
numberlet num: number = 123
stringlet str: string = "Hello World"
nulllet x: null = null
undefinedlet x: underfined = underfined

undefined 和 null 是所有类型的子类型。这两个类型的值可以赋值给其他类型的变量:

// 这样不会报错
let num: number = undefined
 // 这样也不会报错
let num: number = null

除了基本类型,TS 还提供了void、any、字面量、等类型:

void:表示没有值,通常用于描述方法的返回值

any:表示任意类型,官方并不推荐使用,这样就丢失了类型的特性

字面量:声明的类型就是变量的值,字面量可以是一个可以是多个

let a: 3 // 变量的值只能是3
a = 4 // 这样赋值会报错

let a: 3 | '3' // 变量的值只能是3或'3'
a = '3' // 这样赋值是正确的

数组与元组(tuple)

定义一个数组,通常有两种方式:type[]、数组泛型。

let arr: number[]
let arr: Array<number>

通过类型声明限制了数组存储的数据类型,例如上面声明的两个数组里就只允许存放 number 类型的数据。

元组(tuple)是 TypeScript 新增的概念,它与数组类似但允许列表内出现不同的类型数据,且必须在声明时固定长度。它的定义方式如下:

let tup: [string, number] = ['小明', 25]

函数类型

在 JavaScript 中,定义函数通常有两种方式:函数声明 和 函数表达式。对于一个函数,TypeScript 需要对入参类型、返回类型进行约束:

// 函数声明
function sum(x: number, y: number): number {
    return x + y
}
// 函数表达式
let sum = function (x: number, y: number): number {
    return x + y
};

上面分别用函数声明和函数表达式两种方式定义了一个带有两个number类型的入参及number类型返回值的函数。如果一个函数没有返回值,可声明为void。在这样的声明约束下,入参和返回必须严格遵循约束,不可少传、多传。

可选参数

如果对函数的入参有不确定性,可以用?设置可选参数:

function buildName(firstName: string, lastName?: string) {
    if (lastName) {
        return firstName + ' ' + lastName
    } else {
        return firstName
    }
}

需要注意的是,可选参数必须接在必需参数后面。另外,在 ES6 提出的参数默认值在 TS 中会被识别为可选参数,同样必须接在必需参数后面。

联合类型

当我们声明的变量有可能是多种类型时,可以声明为联合类型string | number。当一个变量被声明为联合类型时,在使用这个变量时,只能调用联合类型所共有的属性及方法

let myFavoriteNumber: string | number;
myFavoriteNumber = 'seven';
myFavoriteNumber = 7;

面向对象

在早期的 JavaScript 中,是通过构造函数实现类的并通过原型链实现继承。在 ES6 才引入了类和 class 语法,TypeScript 除了完全支持 class 语法,同时增加了一些新的东西。

修饰符

TypeScript 引入三种属性修饰符:public、private、protected

  • public:修饰的属性或方法是公有的,可以在任何地方访问,也是默认的修饰符
  • private:修饰的属性或方法是私有的,不允许在声明它的类的外部访问。若需要访问私有属性,可以配置寄存器(getter/setter)属性访问或修改。
  • protected:修饰的属性或方法是受保护的,与 private 修饰符的行为很相似,但不同的是 protected 修饰的成员在子类中允许访问

另外要提一个修饰符,叫:readonly,只读属性修饰符。被修饰的属性只允许读取不允许修改,要注意的是,如果它和其他访问修饰符同时存在的话,需要写在其后面。

抽象类

抽象类既是当我们写一个类时,只是希望它作为父类继承而不希望直接使用该类的实例。对于这样的类,TypeScript 引入了 abstract 关键字对其进行修饰,同时类中的方法也必须用这个关键字修饰。

abstract class Animal {
  public name
  public constructor(name) {
    this.name = name
  }
  public abstract giao()
}

let animal = new Animal()// 这样会报错

需要注意的是,在抽象类中定义的抽象方法必须在子类进行实现。

class Cat extends Animal {
  public giao() {
    console.log('喵!');
  }
}

接口

我们知道类之间可以通过继承实现功能拓展,但是一个类有且只能继承一个类。TypeScript 引入了接口的语法,接口是面向对象中的一个重要概念,有时候不同类之间可以有一些共有的特性,这时候就可以把特性提取成接口,用implements关键字来实现。相比于类的单继承接口是允许类实现多个

interface Eat {
    eat(): void
}
interface Say {
    say(): void
}
class Person implements Eat, Say {
    private name
    eat(): void {}
    say(): void {}
}

泛型

泛型是指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型的一种特性。
一个例子

我们编写一个方法,希望把输入的值返回出来。

function fun(a: number): number {
  return a
}

在这里,我们写死了参数类型为 number,但是如果希望 string 或别的类型也用到这个方法就不可行了。于是引出泛型的写法:

function fun<T>(a: T): T {
    return a;
}

在上例中,我们在函数名后添加了<T>,其中 T 用来指代一种数据类型,同时也为函数返回值指定为 T 类型。在调用时,通过传入参数的具体类型推断 T 的类型。

多个类型参数

定义泛型的时候,可以一次定义多个类型参数:

function fun<T, K>(a: T, b: K): T {
    return a;
}
泛型约束

在使用泛型变量时,因为不知道它是哪种类型,所以不能随意的操作它的属性或方法。我可以通过对泛型进行约束,保证变量类型属于我们所确定的范围:

interface Lengthwise {
    length: number;
}

function outLength<T extends Lengthwise>(arg: T): T {
    console.log(arg.length);
    return arg;
}

上诉例子,我们通过extends限制变量类型必须实现了 Lengthwise 接口,保证变量有length属性。

泛型接口
interface List<T> {
    [index: number]: T,
    length: number
}

let list:List<string> = ['a', 'b', 'c']
泛型类
class GenericNumber<T> {
    value: T;
    add: (x: T, y: T) => T;
    constructor(value: T) {
        this.value = value
    }
}

let number = new GenericNumber<number>(1)
number.add = function (x, y) {
    return x + y
}

类型别名

通过type关键字,我们可以自己定义类型。比如有一组属性都是相同的联合类型,定义类型别名就很有必要。

type myType = number | string

interface Obj {
    attr1: myType
    attr2: myType
}
let obj: Obj = {
    attr1: 1,
    attr2: '2'
}

类型断言

我们可以手动对一些不确定的值指定一个类型,场景多用于联合类型和类型别名。

as语法

type myType = number | string

function getLength(params: myType): number {
    const str = params as string
    if (str.length) return str.length
    return str.toString().length
}

<类型>语法

type myType = number | string

function getLength(params: myType): number {
    const str = params<string>
    if (str.length) return str.length
    return str.toString().length
}

结语

本篇博客写于近期复习 TypeScript 的简单总结,这些对于入门阶段的知识是完全够了。更多内容还是参考官方文档。

参考资料:

TS官方文档

从JS的角度入门TypeScript


coderLeo
15 声望0 粉丝