安装TypeScript
npm install -g typescript
使用tsc全局命令
// 查看 tsc 版本
tsc -v
// 编译 ts 文件
tsc 文件名.ts
为什么要使用TypeScript ?
再学新玩意之前呢, 要问自己为什么要使用它? 它帮咱解决了什么问题? 对咱的技术水平有怎样的帮助和提高? 不要光听别人忽悠就去学习某个知识.
当我学习这玩意的第一个星期, 说实话是有点感觉挫败和烦人的, 这玩意要比 JS 麻烦的多, 添加很多类型的定义,在实战开发中浪费了很多时间, 而且会遇到很多根本看不懂的错误, 但是情况很快的发生了改变, 当我在代码中打入越来越多的类型代码时, 效率就会变的越来越高, 遇到各种傻瓜错误的几率也是越来越少, 在公司的项目中我也越来越多的使用到它, 并且呢也越来越能感受到它的优势 :
- 程序更容易理解
- 问题: 函数或者方法输入输出的参数类型, 外部条件等
- 动态语言的约束: 需要手动调试等过程
- 有了TypeScript: 以上问题代码本身就可以回答
- 效率更高
- 在不同的代码块和定义中进行跳转
- 代码自动补全
- 丰富的接口提示
- 更少的错误
- 编译期间能够发现大部分错误
- 减少一些傻b错误的出现
- 非常好的包容性
- 完全兼容 JavaScript
- 第三方库可以单独编写类型文件
- 大多数项目都支持 TypeScript
就跟谈恋爱一样, 不可能找到一个十全十美的人, 同样语言也是 缺点:
- 增加了学习成本
- 在开发中增加了开发成本
原始数据类型和 Any类型
原始数据类型都遵守这个规则
let 变量名: 类型 = 值类型等于相应的
Null 和 Undefined
- 默认情况下null和undefined是所有类型的子类型。 就是说你可以把 null和undefined赋值给所有类型的变量。
Any类型
- 有时候,我们会想要为那些在编程阶段还不清楚类型的变量指定一个类型。 这些值可能来自于动态的内容,比如来自用户输入或第三方代码库。 这种情况下,我们不希望类型检查器对这些值进行检查而是直接让它们通过编译阶段的检查。
数组和元组
数组
let arr: number[] = [1,2,3];
let arr: Array<number> = [1,2,3];
元组
let arr: [string, number] = ['xxj', 22];
Interface 接口
- 对对象的形状进行描述
- Duck Typing (鸭子类型)
interface Person {
readonly sex: string; // 只读属性
age: number;
name: string;
id?: number; // 可选属性
}
let viking: Person = {
age: 20,
name: 'xxj'
}
Function函数
- 在 JS 中, 函数是一等公民
// 约定输入和输出
function add(x: number, y: number, z?: number): number => {
return x + y
}
add(1, 2);
// 函数赋值
// let add2: (x: number, y: number, z?: number) => number = add;
interface ISum {
(x: number, y: number, z?: number): number
}
let add2: ISum = add;
类型推论 联合类型和类型断言
// 联合类型
// 可访问联合类型里被指定的共用的属性和方法
let numberOrString: string | number;
numberOrString.toString();
numberOrString.valueOf();
// 类型断言
// 有时候你会遇到这样的情况,你会比TypeScript更了解某个值的详细信息。 通常这会发生在你清楚地知道一个实体具有比它现有类型更确切的类型。 通过类型断言这种方式可以告诉编译器,“相信我,我知道自己在干什么”。
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;
}
}
枚举
enum Direction {
Up,
Down,
Left,
Right
}
console.log(Direction.Up); // 0
console.log(Direction[0]); // Up
泛型(Generics)
// 把定义好的类型, 当做参数进行输出
function echo<T>(arg: T): T {
return arg;
}
const result = echo(123);
function swap<T, U>(tuple: [T, U]): [U, T] {
return [tuple[1], tuple[0]]
}
const result2 = swap(['string', 123])
约束泛型
interface IWithLength {
length: number
}
function echoWithLength<T extents IwithLength>(arg: T): T {
return arg
}
const str = echoWithLength('str');
泛型在类和接口中的使用
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);
interface KeyPair<T, U> {
key: T,
value: U
}
let kp1 = KeyPair<number, string> = { key: 1, value: 'string' };
let kp2 = KeyPair<string, number> = { key: 'str', value: 2 };
类型别名, 字面量 和 交叉类型
- 类型别名
类型别名,就是给类型起一个别名,让它可以更方便的被重用。
let sum: (x: number, y: number) => number;
const result = sum(1, 2);
type PlusType = (x: number, y: number) => number;
let sum2: PlusType
// 支持联合类型
type StrOrNumber = string | number;
let res2: StrOrNumber = '123';
res2 = 123;
// 字符串字面量
type Directions = 'Up' | 'Down' | 'Left' | 'Right';
let toWhere: Directions = 'Up';
- 交叉类型
interface IName {
name: string
}
type IPerson = IName & { age: number }
let person: IPerson = { name: 'hello', age: 12}
声明文件
文件名.d.ts
它里面没有任何的实际实现代码, 只有类型声明, 比如: interface, function, class 等等
内置类型
const a: Array<number> = [1,2,3]
// 大家可以看到这个类型,不同的文件中有多处定义,但是它们都是 内部定义的一部分,然后根据不同的版本或者功能合并在了一起,一个interface 或者 类多次定义会合并在一起。这些文件一般都是以 lib 开头,以 d.ts 结尾,告诉大家,我是一个内置对象类型欧
const date: Date = new Date()
const reg = /abc/
// 我们还可以使用一些 build in object,内置对象,比如 Math 与其他全局对象不同的是,Math 不是一个构造器。Math 的所有属性与方法都是静态的。
Math.pow(2,2)
// DOM 和 BOM 标准对象
// document 对象,返回的是一个 HTMLElement
let body: HTMLElement = document.body
// document 上面的query 方法,返回的是一个 nodeList 类型
let allLis = document.querySelectorAll('li')
//当然添加事件也是很重要的一部分,document 上面有 addEventListener 方法,注意这个回调函数,因为类型推断,这里面的 e 事件对象也自动获得了类型,这里是个 mouseEvent 类型,因为点击是一个鼠标事件,现在我们可以方便的使用 e 上面的方法和属性。
document.addEventListener('click', (e) => {
e.preventDefault()
})
Typescript 还提供了一些功能性,帮助性的类型,这些类型,大家在 js 的世界是看不到的,这些类型叫做 utility types,提供一些简洁明快而且非常方便的功能。
// partial,它可以把传入的类型都变成可选
interface IPerson {
name: string
age: number
}
let viking: IPerson = { name: 'viking', age: 20 }
type IPartial = Partial<IPerson>
let viking2: IPartial = { }
// Omit,它返回的类型可以忽略传入类型的某个属性
type IOmit = Omit<IPerson, 'name'>
let viking3: IOmit = { age: 20 }