TypeScript
# 安装

[NPM](https://www.npmjs.com/)全局安装[TypeScript](https://www.npmjs.com/package/typescript)模块
```bash
npm install typescript -g
```

# 编译

TypeScript文件均以ts为后缀的文件，所以可以命名xxx.ts文件，并用命令行执行tsc xxx.tx
```ts
tsc xxx.ts
```

# 类型

TypeScript支持与JavaScript几乎相同的数据类型，此外还提供了实用的枚举类型方便我们使用

## 布尔值

最基本的数据类型就是简单的**true**/**false**值，在JavaScript和TypeScript里叫做**boolean**
```ts
let bool: boolean = false;
//=>
var bool = false;
```

## 数字

和JavaScript一样，TypeScript里的所有数字都是浮点数。 这些浮点数的类型是 number。 除了支持十进制和十六进制字面量，TypeScript还支持ECMAScript 2015中引入的二进制和八进制字面量
```ts
let num: number = 9;
//=>
var num = 9;
```

## 字符串

JavaScript程序的另一项基本操作是处理网页或服务器端的文本数据。 像其它语言里一样，我们使用 string表示文本数据类型。 和JavaScript一样，可以使用双引号（ "）或单引号（'）表示字符串
```ts
let str: string = `Wscats ${bool?"is":"isn't"} ${num} years old`;
//=>
var str = "Wscats " + (bool ? "is" : "isn't") + " " + num + " years old";
```

## 数组

TypeScript像JavaScript一样可以操作数组元素。 有两种方式可以定义数组。 可以在元素类型后面接上 []，表示由此类型元素组成的一个数组
```ts
let arr: string[] = ["Oaoafly", "Corrine", "Eno"];
let arr: Array<number> = [1, 2, 3];
//=>
var arr = ["Oaoafly", "Corrine", "Eno"];
```

## 元组

元组类型允许表示一个已知元素数量和类型的数组，各元素的类型不必相同。 比如，你可以定义一对值分别为 string和number类型的元组
```ts
let tuple: [string, number];
tuple = ['hello', 10];
//=>
var tuple;
tuple = ['hello', 10];
```

## Any

有时候，我们会想要为那些在编程阶段还不清楚类型的变量指定一个类型。 这些值可能来自于动态的内容，比如来自用户输入或第三方代码库。 这种情况下，我们不希望类型检查器对这些值进行检查而是直接让它们通过编译阶段的检查。 那么我们可以使用 any类型来标记这些变量
```ts
let notSure: any = 8;
let list: any[] = [false, 9, "Wscats"];
//=>
var notSure = 8;
var list = [false, 9, "Wscats"];
```

## Void

某种程度上来说，void类型像是与any类型相反，它表示没有任何类型。 当一个函数没有返回值时，你通常会见到其返回值类型是 void
```ts
function warning(): void {
    console.log("This is my warning message");
}
//=>
function warning() {
    console.log("This is my warning message");
}
```
声明一个void类型的变量没有什么大用，因为你只能为它赋予undefined和null
```ts
let warning: void = undefined;
```

## Null和Undefined

TypeScript里，undefined和null两者各自有自己的类型分别叫做undefined和null。 和void相似，它们的本身的类型用处不是很大
```ts
let u: undefined = undefined;
let n: null = null;
```
默认情况下null和undefined是所有类型的子类型。 就是说你可以把 null和undefined赋值给number类型的变量

## Never
never类型表示的是那些永不存在的值的类型。 例如， never类型是那些总是会抛出异常或根本就不会有返回值的函数表达式或箭头函数表达式的返回值类型； 变量也可能是 never类型，当它们被永不为真的类型保护所约束时

never类型是任何类型的子类型，也可以赋值给任何类型；然而，没有类型是never的子类型或可以赋值给never类型（除了never本身之外）。 即使 any也不可以赋值给never
```ts
// 返回never的函数必须存在无法达到的终点
function error(message: string): never {
    throw new Error(message);
}

// 推断的返回值类型为never
function fail() {
    return error("Something failed");
}

// 返回never的函数必须存在无法达到的终点
function infiniteLoop(): never {
    while (true) {
    }
}
```

# 接口

类型检查器会查看getInfo的调用。 getInfo有一个参数，并要求这个对象参数有一个名为name类型为string的属性。 需要注意的是，我们传入的对象参数实际上会包含很多属性，但是编译器只会检查那些必需的属性是否存在，并且其类型是否匹配
```ts
interface objValue {
	name: string;
}

function getInfo(obj: objValue) {
	console.log(obj.name);
}

let myObj = {
	age: 10,
	name: "Wscats"
};
getInfo(myObj);
```

> 接口能够描述JavaScript中对象拥有的各种各样的外形。 除了描述带有属性的普通对象外，接口也可以描述函数类型

```ts
interface addValue {
	sum: number,
	good: string
}
function add(x: number, y: number, good: string): addValue {
	return {
		sum: x + y,
		good: good
	};
}
//=>相当于
function add(x: number, y: number, good: string): {
	sum: number,
	good: string
} {
	return {
		sum: x + y,
		good: good
	};
}
//=>相当于
interface Fn {
    (x: number, y: number, good: string): {
        sum: number,
        good: string
    };
}

const add: Fn = function (x, y, good) {
    return {
        sum: x + y,
        good: good
    };
}
```

接口还可以继承
```js
class Control {
    age: number;
}
interface AnimalType extends Control {
    name: String;
    eat(food: String);
}
// 或者
interface PersonType {
    height: number
}
interface AnimalType extends PersonType {
    name: String;
    eat(food: String);
}
const god: AnimalType = {
    name: 'god',
    height: 18,
    eat() { }
}
```

# 类

传统的JavaScript程序使用函数和基于原型的继承来创建可重用的组件，但对于熟悉使用面向对象方式的程序员来讲就有些棘手，因为他们用的是基于类的继承并且对象是由类构建出来的。 从ECMAScript 2015，也就是ECMAScript 6开始，JavaScript程序员将能够使用基于类的面向对象的方式。 使用TypeScript，我们允许开发者现在就使用这些特性，并且编译后的JavaScript可以在所有主流浏览器和平台上运行，而不需要等到下个JavaScript版本

```ts
class Greeter {
	greeting: string;
	constructor(message: string) {
		this.greeting = message;
	}
	greet(): string {
		return "Hello, " + this.greeting;
	}
}
let greeter = new Greeter("world");
//=>
var Greeter = /** @class */ (function () {
    function Greeter(message) {
        this.greeting = message;
    }
    Greeter.prototype.greet = function () {
        return "Hello, " + this.greeting;
    };
    return Greeter;
}());
var greeter = new Greeter("world");
```

# 类类型 && implements

配合`interface`对`class`的类型进行约束
```js
// implements 就是：实现的意思。
// 类实现接口本质上也是一样的，即类遵循接口的约束，接口里面写了多少个函数、参数，实现的类里面也要写相同的函数、参数。
; (() => {
    interface AnimalType {
        name: String;
        eat(food: String);
    }
    // Cat类需要遵循AnimalType的类型
    class Cat implements AnimalType {
        constructor(name: string) {
            this.name = name
        }
        name: String;
        eat(food) {
            console.log(this.age)
            console.log(this.name + food);
        }
    }

    class Lion extends Cat implements AnimalType {
        constructor(name: string) {
            super(name)
        }
    }
    let Tom = new Cat('Tom');
    let King = new Lion('King');
    console.log(Tom.name);
    King.eat('Apple');
})()
```

# 函数

函数是JavaScript应用程序的基础。 它帮助你实现抽象层，模拟类，信息隐藏和模块。 在TypeScript里，虽然已经支持类，命名空间和模块，但函数仍然是主要的定义 行为的地方。 TypeScript为JavaScript函数添加了额外的功能，让我们可以更容易地使用
```ts
let f = (x: number, y: number): number => {
	console.log(1)
	return x + y
}
f(8, 9)
//=>
var f = function (x, y) {
    console.log(1);
    return x + y;
};
f(8, 9);
```

## 可选参数和默认参数

- JavaScript里，每个参数都是可选的，可传可不传。 没传参的时候，它的值就是undefined。 在TypeScript里我们可以在参数名旁使用?实现可选参数的功能
- 在TypeScript里，我们也可以为参数提供一个默认值当用户没有传递这个参数或传递的值是undefined时。 它们叫做有默认初始化值的参数
```ts
let f = (x: number, y: number, good ? : string, shop = "gz"): number => {
	console.log(good, shop)
	return x + y
}

f(8, 9, "mobile")
f(8, 9)
=>
var f = function (x, y, good, shop) {
    if (shop === void 0) { shop = "gz"; }
    console.log(good, shop);
    return x + y;
};
f(8, 9, "mobile");
f(8, 9);
```
接口也同样支持可选参数，但不支持默认参数
```ts
interface SquareConfig {
    color?: string;
    width?: number;
}

interface SquareResult {
    width?: number;
    color?: string;
    area?: number;
}

function createSquare(config: SquareConfig): SquareResult {
    return {
        color: config.color,
        area: 14
    }
}

let mySquare = createSquare({ color: "red" });
```