TypeScript
编程语言的类型
- 动态类型语言
- 不用声明数据类型
- 静态类型语言
- 需要声明数据类型
静态类型 VS 动态类型
- 需要声明数据类型
一、TypeScript 究竟是什么
- JavaScript that scales(可扩展的 JavaScript)
- 静态类型风格的类型系统
- 从 es6 到 es10 甚至是 esnext 的语法支持
- 兼容各种浏览器,各种系统,各种服务器,完全开源
二、为什么要使用TypeScript
1. 程序更容易理解
- 问题:函数或者方法输入输出的参数类型,外部条件等
- 动态语言的约束:需要手动调试等过程
- 有了 TypeScript: 代码本身就可以回答上诉问题
2. 效率更高
- 在不同的代码快和定义中跳转
- 代码自动补全
- 丰富的接口提示
3. 更少的错误
- 编译期间能够发现大部分错误
- 杜绝一些比较常见错误
4. 非常好的包容性
- 完全兼容 JavaScript
- 第三方库可以单独编写类型文件
- 大多数项目都支持TypeScript
三、环境搭建
1. 安装
npm install typescript -g
tsc -V
2. 运行
// 将 ts 转换成 js
tsc demo.ts
// 执行 js
tsc demo.js
npm install -g ts-node
// 直接执行 ts
ts-node demo.ts
四、基础语法
1. 原始数据类型和 Any 类型
let isDone: boolean = false;
let firstName: string = 'viking';
let message: string = `Hello, ${ firstName }`;
let age: number = 10;
let u: undefined = undefined;
let n: null = null;
let num: number = undefined;
let Person: {
name: string,
age: number
} = {
name: 'kstring',
age: 19
}
ts 声明类型后不能赋值其他的类型,否则会报错
any
任意类型,可以任意调用方法、属性和赋值其他类型,丧失类型检查的作用,在有明确的类型是不建议使用,以免引起不必要的错误
let notSure: any = 4;
notSure = 'string';
notSure = true;
notSure.myName;
notSure.getName();
2. 数组和元组
let arrOfNumbers: number[] = [1, 2, 3];
元组: 一定成度上限制了数据类型的数组
// 元素不能多也不能少
let user: [string, number] = ['kstring', 19];
// 拥有数组方法,但只能添加元组中定义的类型,否则会报错
user.push('king'); // [ 'kstring', 20, 'king' ]
user.shift(); // [ 20, 'kstring' ]
// 二维元组
const teacherList: [string, string, number][] = [
['dell', 'male', 19],
['sun', 'female', 26],
['jen', 'fem', 38]
]
3. Interface 接口
-
对对象的形状 (shape) 进行描述
-
Duck Typing (鸭子类型)
- 对象类型推断的策略,更关注对象如何被使用,而不是对象本身
// 定义接口
interface Person {
// 只读属性
readonly id: number,
name: string,
// 可选属性,
age?: number,
}
let Person: Person = {
id: 2,
name: 'kstring',
age: 19,
}
4. Function 函数
- JS 中,函数是一等公民
- 可以存入数组,作为参数,也可以作为返回值
// 可选参数后不能参加确定参数,与对象的可选属性不同
const add = (x: number, y: number, z?: number):number => {
if (z) {
return x + y + z;
}
return x + y;
}
// 注意:这里 => 是在声明返回值类型,并不是 ES6 中的箭头函数
let add2: (x: number, y: number, z) => number = add
对象类型注解
function add ({ x, y }: { x: number, y: number }) {
return x + y;
}
add({ x: 1, y: 2 });
注意: 在 ts 中 后都是声明类型,与代码逻辑无关
interface: 描述函数
interface ISum {
// 这里定义返回值为 : , 而非 =>
(x: number, y: number, z): number
}
let add2: ISum = add
5. 类型推论、联合类型、类型断言和类型别名
5.1 类型推论(type inference)
类型推论:自动推导出值得类型
5.2 联合类型(union types)
联合类型:可以指定多种的类型,但只能赋值指定的类型
let numberOrString: number | string
5.3 类型断言(type Assertion)
类型断言:可以用来手动指定一个值的类型
function getLength(input: string | number): number {
const str = input as string;
if (str.length) {
return str.length;
} else {
const number = input as number;
return number.toString().length
}
}
function getLength(input: string | number): number {
if ((<string>input).length) {
return (<string>input).length;
} else {
}
}
5.4 类型别名(type aliases)
类型别名: 类型别名会给一个类型起个新名字。 类型别名有时和接口很像,但是可以作用于原始值,联合类型,元组以及其它任何你需要手写的类型
type Name = string;
function sum(x: number, y: number): number {
return x + y;
}
const sum2: (x: number, y: number) => number = sum;
type: PlusType = (x: number, y: number) => number;
const sum3 = PlusType;
6. class
- 类(Class): 定义了一切事物的抽象特点
- 对象(Object):类的实例
- 面向对象(OOP)三大特性:封装、继承、多态
访问类型
- public:修饰的属性或方法是共有的,允许在类的内外的使用
- protected: 修饰的属性或方法是受保护的,允许在类内及继承的子类中使用
- private: 修饰的属性或方法是私有的,允许在类内被使用
- abstract: 抽象
- readonly: 只读属性
6.1 封装
- 隐藏方法细节,只提供对外的接口,意义保护或者防止代码(数据)被无意中破坏,封装原则高内聚、低耦合
- 内聚:内聚是指一个模块内部各个部分之间的关联程度
- 耦合:耦合指各个模块之间的关联程度
class Animal {
// 私有属性
private sum:number = 0;
getSum():number {
return this.sum;
}
setSum(sum) {
this.sum = sum;
}
}
6.2 继承
- 继承:子类可以继承父类的特征
- 提高代码复用性
class Animal {
name: string;
constructor(name) {
this.name = name;
}
run() {
return this.name;
}
}
class Dog extends Animal {
bark() {
return `${this.name} is barking`
}
}
const tantan = new Dog('tantan');
console.log(tantan.run()); // tantan
console.log(tantan.bark()); // tantan is barking
6.3 多态
- 多态:当不同的对象去完成相同的行为会产生出不同的状态。
- 例如:猫的叫声、狗的叫声,都是在叫,但发出的声音不一样
- 提高了代码扩展性
class Animal {
cry() {
console.log("叫");
}
}
class Dog extends Animal {
cry() {
console.log("汪汪");
}
}
class Cat extends Animal {
cry() {
console.log("喵喵");
}
}
const animal = new Animal();
const dog = new Dog();
const cat = new Cat();
animal.cry(); //叫
dog.cry(); // 汪汪
cat.cry(); // 喵喵
6.4 抽象类
抽象类的作用是实现多个子类中共用的部分, 不用重复写到实现类中
抽象类无法被实例化,只能被继承
abstract class Geom {
abstract getArea(): number;
}
6.5 抽象类与接口的异同点
相同点
- 都不能被实例化
- 都能包含抽象方法.这些抽象方法用于描述系统能提供的服务,但是不必提供具体的实现
- 接口和抽象类是一种数据类型
不同点
- 在抽象类中可以为部分方法提供默认的实现,从而避免了重复实现它们.提高了代码的可重用性.这是抽象类的优势
- 一个类只能继承一个直接的父类(这个父类有可能是抽象类).但是一个类可以实现多个接口,这是接口的优势
7. 类和接口
- 继承的困境
- 一个子类只能有一个父类
- 类可以使用 implements 来实现接口,接口可以实现多个
// 收音机
interface Radio {
switchRadio(trigger: boolean): void;
}
// 电池
interface Battery {
checkBatteryStatus(): void;
}
// 汽车类
class Car implements Radio {
switchRadio(trigger: boolean) {
}
}
// 手机类
class Cellphone implements Radio, Battery {
switchRadio(trigger: boolean) {
}
checkBatteryStatus(): void {
}
}
8. 枚举 enums
维基百科: 在数学和计算机科学理论中,一个集的枚举是列出某些有穷序列集的所有成员的程序,或者是一种特定类型对象的计数。这两种类型经常(但不总是)重叠。 [1] 是一个被命名的整型常数的集合,枚举在日常生活中很常见,例如表示星期的SUNDAY、MONDAY、TUESDAY、WEDNESDAY、THURSDAY、FRIDAY、SATURDAY就是一个枚举。
使用枚举类型可以允许我们定义一些带名字的常量,也可以清晰地表达意图或创建一组有区别的用例。在 TypeScript 中,支持数字的和基于字符串的枚举。枚举是对 js 标准数据类型的补充,声明一组带名字的常量 一定范围内常量,比如星期一到星期五,
推荐阅读 TypeScript 枚举类型用法示例 typescript 中文网
enum Direction {
Up,
Down,
Left,
Right
}
console.log(Direction.Up); // 0
console.log(Direction[0]); // Up
枚举前面加个 const 可以减少开销
cosnt enum Direction {
Up,
Down,
Left,
Right
}
9. 泛型 generics
泛型: 类型的参数化,就是把类型像方法的参数一样传递
function echo<T>(arg: T): T {
return arg;
}
// 传入的布尔值返回的还是布尔值
const result = echo(true)
function swap<T, U>(tuple: [T, U]): [U, T] {
return [tuple[1], tuple[0]];
}
const result2 = swap(['string', 123]);
10. 约束泛型
interface IWithLength {
length: number
}
// 约束传递参数必须有 length 属性
function echoWithLength<T extends IWithLength>(arg: T): T {
console.log(arg.length);
return arg;
}
const str = echoWithLength('string');
const obj = echoWithLength({ length: 20 });
const arr = echoWithLength([1, 2, 3]);
// echoWithLength(13) // 报错
11. 泛型在类和接口中的使用
类:
class Queue<T> {
private data = [];
push(item: T) {
return this.data.push(item);
}
pop(): T {
return this.data.shift();
}
}
const queue = new Queue<number>();
queue.push(1);
console.log(queue.pop().toFixed());
接口:
interface KeyPair<T, U> {
key: T,
value: U
}
let kp1: KeyPair<number, string> = {
key: 1,
value: 2
}
let arr: number[] = [1, 2, 3];
let arrTwo: Array<number> = [1, 2, 3]
12. 声明文件
TypeScript 是 JavaScript 的超集,相比 JavaScript,其最关键的功能是静态类型检查 (Type Guard)。然而 JavaScript 本身是没有静态类型检查功能的,TypeScript 编译器也仅提供了 ECMAScript 标准里的标准库类型声明,只能识别 TypeScript 代码里的类型。所以对于一些第三库就需要一些声明文件, 声明文件以 .d.ts 结尾。
也可以理解为翻译文件,用来翻译 js 代码,大多数第三方库都有自己的声明文件,不需要自己书写
npm install --save jquery
// jquery 的声明文件
npm install --save @types/jquery