Typescript学习知识总结

导语:随着Vue3引入了Typescript,至此前端三大js框架都支持了使用typescript开发WEB项目。那么现在就来总结一下前段时间学习ts的知识点,进行一些总结归纳,做一个学习笔记。

# 目录

  • 概念
  • 补充
  • 安装配置
  • 常用知识

# 概念

TypeScript (opens new window)是一门由微软的DelphiC#发明者安德斯·海尔斯伯格开发的开源和跨平台的强类型的静态类型的编译型编程语言。它是JavaScript的一个超集,而且本质上向这个语言添加了可选的静态类型和基于类的面向对象编程。

# 补充

下面简单描述一下几个概念的含义。

  • 解释型和编译型语言
  • 强类型和弱类型
  • 静态类型和动态类型语言

# 解释型和编译型语言

  • 产生原因

计算机只能理解机器语言,不能直接理解识别和执行高级编程语言,所以把高级编成语言需要层层转换成机器语言。在转换的过程中,有两种方式可供参考:编译和解释。

转换简化流程: 高级语言 --> 汇编语言 --> 机器语言

编程语言从执行原理上可分为编译型语言和解释型语言。

  • 编译型语言

这类型的语言使用专门的编译器(Compiler),针对特定的平台,将高级语言源码一次性编译成机器码,并执行。

执行速度快,对系统要求不高,适用于开发操作系统,大型应用程序,数据库系统等。

优点:运行速度快,代码效率高,禁止修改,安全保密;
缺点:需要编译才能运行,可移植性差,兼容性差;

常见的有:cc++Delphi等;

  • 解释型语言

这类型的语言使用专门的解释器(Interpreter),对源码进行逐行进行解释成机器码并执行。

执行速度比较低,解释一行,执行一行。

优点:可移植性好,只要具备解释环境,就可以跨系统运行;动态调试程序;
缺点:运行需要解释环境,运行比编译慢;占用资源较多;代码效率低;对平台的依赖程度很严重;

常见的有:Java,JavaScript, Python等;

# 强类型和弱类型、静态类型和动态类型语言

下面是网上的几张图:

弱类型、强类型、动态类型、静态类型

弱类型、强类型、动态类型、静态类型

  • 强类型和弱类型

强类型语言是一种强制定义类型的语言,所有的变量都必须先定义后使用,严格符合定义的类型,不经强制转换,不更改定义的类型。例如:java,.NET,C++

弱类型语言是一种类型可以被忽略的,不需要强制定义的变量类型的一种语言,但是也有基本的类型判断方法进行显性或者隐形的类型转换。例如:javascript,php,vb等。

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

静态类型语言是一种在程序运行期间做数据类型检查的语言。在编程的过程中,不需要指定数据类型。该语言会当你第一次赋值的时候,在内部记录下来这个变量的数据类型。比如:Python,Ruby

动态类型语言是一种在程序编译期间做数据类型检查的语言。在编程的过程中,要声明所有变量的数据类型。比如C,C++,C#,Java

StaTIc typing when possible, dynamictyping when needed.

# 安装配置

  • npm全局安装ts
npm install -g typescript
1
  • 查看版本
$ tsc -v
Version 4.3.5
1
2
  • 命令行

使用tsc --help可以查看所有的命令以及对应的描述。

常用的有

-w, --watch(监听文件内容实时编译), --outfile file.js file.ts指定输出文件名称,
--sourceMap生成一个源码地图,
-d, --declaration生成相应的“.d.ts”文件,
--removeComments输出时去掉注释信息;
-b, --build构建一个或多个项目及其依赖项;

# 常用知识

# 日常类型

  • 字符串string
  • 数值number
  • 布尔boolean
  • 数组[]
  • 任何any
  • 联合类型
  • 对象类型

默认情况下,ts会自动判断代码中的数据类型,当你不知道这个变量改赋予什么类型的时候,或者不希望类型检查时候报错,可以使用any

联合类型可以让变量拥有两个或者多个类型组成的类型,任何其中一种都可以。

举例:

// demo.ts
const myName: string = 'mark';
const age: number = 18;
const flag: boolean = true;
const hobby: string[] = ['eat','play','read'];
const other: any = { x: 0 };
let printId: string | number = 10;
let printId: string | number = '10';

type Point = {
    x: number,
    y: number
}

let pos: Point = {
    x: 20,
    y: 18
}

let myPos = `My current coordinates are (${pos.x},${pos.y}) !;`
console.log(myPos);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

我们运行一下这个demo.ts

tsc demo.ts --watch
1

以下是运行结果

// demo.js
var myName = 'mark';
var age = 18;
var flag = true;
var hobby = ['eat', 'play', 'read'];
var other = { x: 0 };
var printId = 10;
var userId = '10';

var pos = {
    x: 20,
    y: 18
};
var myPos = "My current coordinates are (" + pos.x + "," + pos.y + ") !;";
1
2
3
4
5
6
7
8
9
10
11
12
13
14

对象类型 :

类型别名type和接口interface都可以用于定义对象类型,但是区别是接口可以添加新属性字段和扩展接口。

比如:定义一个Animal的对象类型。

类型别名是:

// type
type Animal = {
    name: string
}


// 添加新属性报错
type Animal = {
    age: number
}
// Error: Duplicate identifier 'Animal'.

// 扩展需要这样
type Bear = Animal & {
    honey: boolean
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

接口类型是:

// interface
interface Animal {
    name: string
}

interface Animal {
    age: number
}

interface Bear extends Animal {
    honey: boolean
}
1
2
3
4
5
6
7
8
9
10
11
12

# 函数方法

包括匿名函数,参数类型和返回类型,可选属性等定义方法。

比如传入的参数是number,返回string,不返回可以不写或者写void()

//demo.ts

function sayAge (age: number): string {
    return `我今年${age}岁了。`;
}

sayAge(18);

// 箭头函数
const sayAgeTwo = (age: number): void => console.log(`我今年${age}岁了。`);
sayAge(18);

function showHobby (arr: string[]):void {
    arr.forEach((item) => {
        console.log(item);
    })
}

showHobby(hobby);

// 可选参数
function printName(obj: { first: string; last?: string }) {
    let { first, last } = obj;
    let result = last ? `${first} ${last}` : first;
    console.log(`My name is ${result}`);
}

// Both OK
printName({ first: "Kwan" });
printName({ first: "Kwan", last: "Chih" });
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

编译一下:

//demo.ts
function sayAge(age) {
    return "\u6211\u4ECA\u5E74" + age + "\u5C81\u4E86\u3002";
}

var saResult = sayAge(18);
console.log(saResult); // 我今年18岁了。

var sayAgeTwo = function (age) { return console.log("\u6211\u4ECA\u5E74" + age + "\u5C81\u4E86\u3002"); };

sayAgeTwo(18); // 我今年18岁了。

function showHobby(arr) {
    arr.forEach(function (item) {
        console.log(item);
    });
}
showHobby(hobby);
// eat
// play
// read
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

# 类class

typescript完全支持ES2015中引入的class关键字及其用法。

包括:

  • 基本类
class Parent {}
1
  • 构造函数
class Parent {
    constructor () {}
}
1
2
3
  • 方法
class Parent {
    constructor () {}

    methodName () {
        // something
    }
}
1
2
3
4
5
6
7
  • 只读,受保护,隐私,静态
class Parent {

    public name: string = ''; // 隐私
    private age: number = ''; // 受保护
    static sex: boolean = ''; // 静态
    readonly leg:  = ''; // 只读
}
1
2
3
4
5
6
7
  • 继承 super
class child extends Parent {
    constructor () {
        super();
    }
}
1
2
3
4
5

举例说明:一个动物类

// class.ts
interface animalInfo {
    name: string, 
    age?: number, 
    sex?: boolean
}

class Animal {

    public name: string;
    private age: number;
    private sex: boolean;

    constructor (obj: animalInfo) {
        this.name = obj.name;
        this.age = obj.age;
        this.sex = obj.sex;
    }

    public sayName () {
        console.log(`My name is ${this.name}.`);
    }

    sayAge () {
        console.log(`My age is ${this.age}.`);
    }

    private saySex () {
        console.log(`My sex is ${this.sex}.`);
    }

}

class Dock extends Animal {

    readonly leg: number | string;
    static prop: string = 'animal';

    constructor (obj: animalInfo, leg: number | string) {
        super(obj);
        this.leg = leg;
    }

    showLeg () {
        console.log(`Dock ${this.name} has ${this.leg} legs.`);
    }

    printThis () {
        console.log(`this is ${JSON.stringify(this)}.`);
    }

}

let dog = new Animal({name: 'sherry'});
dog.sayName(); // My name is sherry.

let dock = new Dock({name: 'tang'}, 'two');
dock.showLeg(); // Dock tang has two legs.
dock.printThis(); // this is {"name":"tang","leg":"two"}.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59

# 模块modules

TS的模块也支持ES2015的模块importexport,以及commonjs的requiremodule.exports

这个语法就不说了,都懂得。

我还是写了一个小例子。

//hello.ts
export default function hello () {
    console.log('Hello,World!');
}
1
2
3
4
// math.ts
export class Mathcalc {

    private a: number;
    private b: number;

    constructor (a: number ,b: number) {
        this.a = a;
        this.b = b;
    }

    add () {
        return this.a+this.b;
    }

    subtract () {
        return this.a-this.b;
    }

    multiply () {
        return this.a*this.b;
    }

    divide () {
        return this.a/this.b;
    }

}

export function sayHi (name: string) {
    console.log('Hi,', name);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// mk.ts
import hello from './hello.js';
import {
    Mathcalc,
    sayHi
} from './math.js'

hello(); // Hello,World!

let m1 = new Mathcalc(5,10);

console.log(m1.add()); // 15
console.log(m1.subtract()); // -5
console.log(m1.multiply()); // 50
console.log(m1.divide()); // 0.5

sayHi('Mark'); // Hi, Mark

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

编译后的js内容如下:

// hello.js
"use strict";
exports.__esModule = true;
function hello() {
    console.log('Hello,World!');
}
exports["default"] = hello;
1
2
3
4
5
6
7
// math.js
"use strict";
exports.__esModule = true;
exports.sayHi = exports.Mathcalc = void 0;
var Mathcalc = /** @class */ (function () {
    function Mathcalc(a, b) {
        this.a = a;
        this.b = b;
    }
    Mathcalc.prototype.add = function () {
        return this.a + this.b;
    };
    Mathcalc.prototype.subtract = function () {
        return this.a - this.b;
    };
    Mathcalc.prototype.multiply = function () {
        return this.a * this.b;
    };
    Mathcalc.prototype.divide = function () {
        return this.a / this.b;
    };
    return Mathcalc;
}());
exports.Mathcalc = Mathcalc;
function sayHi(name) {
    console.log('Hi,', name);
}
exports.sayHi = sayHi;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// mk.js
"use strict";
exports.__esModule = true;
var hello_js_1 = require("./hello.js");
var math_js_1 = require("./math.js");
hello_js_1["default"]();
var m1 = new math_js_1.Mathcalc(5, 10);
console.log(m1.add()); // 15
console.log(m1.subtract()); // -5
console.log(m1.multiply()); // 50
console.log(m1.divide()); // 0.5
math_js_1.sayHi('Mark'); // Hi,  Mark
1
2
3
4
5
6
7
8
9
10
11
12

# 其他知识点

# 枚举(扩展类型)

可以定义一组命名常量,基于数字和字符串。

例如:

enum Direction {
    up,
    down,
    left,
    right
}

console.log(Direction.up); // 0
console.log(Direction[3]); // right

enum httpStatus {
    success = 200,
    timeout = 504,
    notfound = 404,
    redirect = 301
}

console.log(httpStatus[200]); // success
console.log(httpStatus.redirect); // 301
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

编译以后

var Direction;
(function (Direction) {
    Direction[Direction["up"] = 0] = "up";
    Direction[Direction["down"] = 1] = "down";
    Direction[Direction["left"] = 2] = "left";
    Direction[Direction["right"] = 3] = "right";
})(Direction || (Direction = {}));
console.log(Direction.up); // 0
console.log(Direction[3]); // right
var httpStatus;
(function (httpStatus) {
    httpStatus[httpStatus["success"] = 200] = "success";
    httpStatus[httpStatus["timeout"] = 504] = "timeout";
    httpStatus[httpStatus["notfound"] = 404] = "notfound";
    httpStatus[httpStatus["redirect"] = 301] = "redirect";
})(httpStatus || (httpStatus = {}));
console.log(httpStatus[200]);
console.log(httpStatus.redirect);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# 泛型

之前提到的都是一个或者两个类型,有时候不够灵活多样,ts中泛型功能为构建大型软件工程项目提供了很好的支持。

下面写一个简单的泛型函数。

// id.ts
interface CommonIdentity<Type> {
    (arg: Type): Type
}

function identity<Type>(args: Type): Type {
    return args;
}

let myId : CommonIdentity<number> = identity;
console.log(myId(10)); // 10

let myStr : CommonIdentity<string> = identity;
console.log(myStr('hello')); // hello

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 命名空间

这样是js变量空间冲突的问题频发的原因之一,ts提供命名空间,互不冲突,易于维护。

命名空间还可以引用。

比如以下这个例子:

// isNum.ts
namespace testNum {
    export interface testNumStr {
        isAccept (s: string): boolean;
    }
}

// ns.ts
/// <reference path="isNum.ts" />
namespace Vaildate {
    export interface Person {
        name: string,
        age?: number,
        sex?: boolean
    }

    export function isOdd (num: number):boolean {
        return num % 2 == 0;
    }

    export function myName (person: Vaildate.Person): string {
        return `My name is ${person.name}.`
    }

    const numReg: RegExp = /^[A-Za-z]+$/;

    export class numRegExp implements testNum.testNumStr {
        isAccept (s: string) {
            return numReg.test(s);
        }
    }
}

let myName = Vaildate.myName({name: 'mark'});
let myNum = Vaildate.isOdd(6);

console.log(myName); // My name is mark.
console.log(myNum); // true
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

# 声明文件

如果一个库没有配置d.ts文件的话,而你又把这个库放到了你的项目里面,这个项目使用ts,那你就要为这个库编写一个d.ts文件,以便你的库可以很好的不报错的被使用。

下面是举个例子:

比如我有个方法,就是求和公式,然后配置声明。

// sum.ts
function sum (arr: number[]): number {
    let num = 0;
    for (const item of arr) {
        num += item;
    }
    return num;
}

export default sum;
1
2
3
4
5
6
7
8
9
10

如果你自己不想手写声明文件,你可以使用-d这个参数来自动生成。

tsc sum.ts -d
1

看下生成后的文件。

// sum.js
"use strict";
exports.__esModule = true;
function sum(arr) {
    var num = 0;
    for (var _i = 0, arr_1 = arr; _i < arr_1.length; _i++) {
        var item = arr_1[_i];
        num += item;
    }
    return num;
}
exports["default"] = sum;
1
2
3
4
5
6
7
8
9
10
11
12
// sum.d.ts
declare function sum(arr: number[]): number;
export default sum;
1
2
3

以上就是ts的基础知识内容总结归纳了。

分享至:

  • qq
  • qq空间
  • 微博
  • 豆瓣
  • 贴吧