鸿蒙生态让TS再次🔥了起来,我们来简单谈谈TypeScript 和 JavaScript的对比吧

268 阅读5分钟

阮一峰 博客 ts.xcatliu.com

1.基本说明

我们知道,JavaScript 是一门非常灵活的编程语言。它没有类型约束,一个变量可能初始化时是字符串,过一会儿又被赋值为数字。

由于隐式类型转换的存在,有的变量的类型很难在运行前就确定。

基于原型的面向对象编程,使得原型上的属性或方法可以在运行时被修改。

函数是 JavaScript 中的一等公民[2],可以赋值给变量,也可以当作参数或返回值。

TypeScript是静态类型,指编译阶段就能确定每个变量的类型,这种语言的类型错误往往会导致语法错误。TypeScript在运行前需要先编译为 JavaScript,而在编译阶段就会进行类型检查;

而Javascript是动态类型,它是属于解释性语言,没有编译阶段。

2.弱类型。

允许隐式类型转换,这一点javascript是相同的。

3.安装:npm install -g typescript

创建:tsc hello.ts

我们约定使用 TypeScript 编写的文件以 .ts 为后缀,用 TypeScript 编写 React 时,以 .tsx 为后缀

4.TypeScript 编译的时候即使报错了,还是会生成编译结果javascript文件,我们仍然可以使用这个编译之后的文件。

如果要在报错的时候终止 js 文件的生成,可以在 tsconfig.json 中配置 noEmitOnError 即可!

5.基础

5.1原始数据类型:boolean,boolean 是 JavaScript 中的基本类型,而 Boolean 是 JavaScript 中的构造函数

number,string,void,unddefined,null,与 void 的区别是,undefined 和 null 是所有类型的子类型

其中 ` 用来定义 ES6 中的模板字符串,${expr} 用来在模板字符串中嵌入表达式

// 模板字符串

let sentence: string = `Hello, my name is ${myName}.

I'll be ${myAge + 1} years old next month.`;

5.2任意值

任意值(Any)用来表示允许赋值为任意类型。变量如果在声明的时候,未指定其类型,那么它会被识别为任意值类型

let myFavoriteNumber: any = 'seven';

myFavoriteNumber = 7;

5.3联合类型:联合类型(Union Types)表示取值可以为多种类型中的一种。

let myFavoriteNumber: string | number;

myFavoriteNumber = 'seven';

myFavoriteNumber = 7;

6.对象的类型:接口,在 TypeScript 中,我们使用接口(Interfaces)来定义对象的类型。

interface Person {

    name: string;

    age: number;

}

let tom: Person = {

    name: 'Tom',

    age: 25

};

6.1可选属性

有时我们希望不要完全匹配一个形状,那么可以用可选属性:

interface Person {

    name: string;

    age?: number;

}

let tom: Person = {

    name: 'Tom'

};

6.2任意属性

interface Person {

    name: string;

    age?: number;

    [propName: string]: any;

}

let tom: Person = {

    name: 'Tom',

    gender: 'male'

};

6.3只读属性:有时候我们希望对象中的一些字段只能在创建的时候被赋值,那么可以用 readonly 定义只读属性

注意,只读的约束存在于第一次给对象赋值的时候,而不是第一次给只读属性赋值的时候

7.数组的类型

「类型 + 方括号」来表示数组

let fibonacci: number[] = [1, 1, 2, 3, 5];

数组泛型:我们也可以使用数组泛型(Array Generic) Array 来表示数组:

let fibonacci: Array = [1, 1, 2, 3, 5];

接口表示数组:

interface NumberArray {

    [index: number]: number;

}

let fibonacci: NumberArray = [1, 1, 2, 3, 5];

any 在数组中的应用:用 any 表示数组中允许出现任意类型

let list: any[] = ['xcatliu', 25, { website: 'xcatliu.com' }];

8.函数的类型

let mySum: (x: number, y: number) => number = function (x: number, y: number): number {

    return x + y;

};

8.1可选参数:我们用 ? 表示可选的参数,可选参数后面不允许再出现必需参数了。

8.2剩余参数

function push(array, ...items) {

    items.forEach(function(item) {

        array.push(item);

    });

}

let a: any[] = [];

push(a, 1, 2, 3);

8.3重载:重载允许一个函数接受不同数量或类型的参数时,作出不同的处理。

function reverse(x: number | string): number | string | void {

    if (typeof x === 'number') {

        return Number(x.toString().split('').reverse().join(''));

    } else if (typeof x === 'string') {

        return x.split('').reverse().join('');

    }

}

9.类型断言,值 as 类型

interface Cat {

    name: string;

    run(): void;

}

interface Fish {

    name: string;

    swim(): void;

}

function isFish(animal: Cat | Fish) {

    if (typeof (animal as Fish).swim === 'function') {

        return true;

    }

    return false;

}

联合类型可以被断言为其中一个类型

父类可以被断言为子类

任何类型都可以被断言为 any

any 可以被断言为任何类型

10.声明文件:声明文件必需以 .d.ts 为后缀。

11.内置对象

进阶----------------------------------------------------------

12.类型别名:类型别名用来给一个类型起个新名字。我们使用 type 创建类型别名

type Name = string;

type NameResolver = () => string;

type NameOrResolver = Name | NameResolver;

function getName(n: NameOrResolver): Name {

    if (typeof n === 'string') {

        return n;

    } else {

        return n();

    }

}

13.字符串字面量类型:我们使用 type 定了一个字符串字面量类型 EventNames,它只能取三种字符串中的一种。

type EventNames = 'click' | 'scroll' | 'mousemove';

function handleEvent(ele: Element, event: EventNames) {

    // do something

}

handleEvent(document.getElementById('hello'), 'scroll');  // 没问题

handleEvent(document.getElementById('world'), 'dblclick'); // 报错,event 不能为 'dblclick'

14.元组:而元组(Tuple)合并了不同类型的对象

当直接对元组类型的变量进行初始化或者赋值的时候,需要提供所有元组类型中指定的项。

let tom: [string, number];

tom = ['Tom', 25];

15.枚举

enum Days {Sun, Mon, Tue, Wed, Thu, Fri, Sat};

常数枚举

const enum Directions {

    Up,

    Down,

    Left,

    Right

}

外部枚举

declare enum Directions {

    Up,

    Down,

    Left,

    Right

}

16.类

extends 继承:使用 extends 关键字实现继承,子类中使用 super 关键字来调用父类的构造函数和方法

static:使用 static 修饰符修饰的方法称为静态方法,它们不需要实例化,而是直接通过类来调用:

abstract 用于定义抽象类和其中的抽象方法。抽象类是不允许被实例化的,抽象类中的抽象方法必须被子类实现

TypeScript支持接口继承类

class Point {

    x: number;

    y: number;

    constructor(x: number, y: number) {

        this.x = x;

        this.y = y;

    }

}

interface Point3d extends Point {

    z: number;

}

TypeScript 可以使用三种访问修饰符(Access Modifiers),分别是 public、private 和 protected。

public 修饰的属性或方法是公有的,可以在任何地方被访问到,默认所有的属性和方法都是 public 的

private 修饰的属性或方法是私有的,不能在声明它的类的外部访问

protected 修饰的属性或方法是受保护的,它和 private 类似,区别是它在子类中也是允许被访问的

17.泛型