概述
- TypeScript(简称:TS)是 JavaScript 的超集(JS 有的 TS 都有)
- TypeScript = Type + JavaScript(在 JS 基础之上,为 JS 添加了类型支持)
- TypeScript 是微软开发的开源编程语言,可以在任何运行 JavaScript 的地方运行
需求
JS 代码中绝大部分错误都是类型错误(Uncaught TypeError)
编程语言的动静来区分:
- TypeScript 属于静态类型的编程语言
-
- 静态类型:编译期做类型检查
- JS 属于动态类型的编程语言
-
- 动态类型:执行期做类型检查
代码编译和代码执行的顺序:1 编译 2 执行
TS 可以提前到在编写代码的同时就发现代码中的错误
优势
- 更早(写代码的同时)发现错误,减少找 Bug、改 Bug 时间,提升开发效率
- 程序中任何位置的代码都有代码提示,随时随地的安全感,增强了开发体验
- 强大的类型系统提升了代码的可维护性,使得重构代码更加容易
- 支持最新的 ECMAScript 语法,优先体验最新的语法,让你走在前端技术的最前沿
- TS 类型推断机制,不需要在代码中的每个地方都显示标注类型,让你在享受优势的同时,尽量降低了成本
擦除类型
实际上没有任何浏览器在未经修改的情况下运行 TypeScript,所以 TypeScript 需要编译器,通过某种方法来删除或转换任何特定于 TypeScript 的代码。大多数特定于 TypeScript 的代码都被删除了,同样地,类型注释也被完全删除了
降级
- ECMAScript从新版本降到旧版本就叫降级,TypeScript 能够将代码从较新版本的 ECMAScript 重写为较旧的版本
- 默认情况下,TypeScript 以 ES3 为目标
tsc --target es2015 hello.ts更改为以 ECMAScript 2015 为目标- 当前绝大多数浏览器都支持 ES2015,可以以es2015为标准,除非很是很古老的浏览器或者项目
严格性
- CLI 中的 strict 标志或 tsconfig.json 中的
"strict": true会将类型检查严格标志全部打开 - noImplicitAny: 对任何类型隐式推断为 any 的变量触发错误
- strictNullChecks:使处理 null 和 undefined 更加明确
使用
安装工具包
Node.js/浏览器,只认识 JS 代码,不认识 TS 代码。需要先将 TS 代码转化为 JS 代码,然后才能运行
安装
npm i -g typescripttsc -v:查看版本- 使用:
tsc hello.ts - 源文件有错误时,不再编译结果:
tsc --noEmitOnError hello.ts
简化运行
使用 ts-node 包,直接在 Node.js 中执行 TS 代码
- 安装:
npm i -g ts-node - 使用:
ts-node hello.ts
常用类型
TS 提供了 JS 的所有功能,并且额外的增加了:类型系统
- 所有的 JS 代码都是 TS 代码
- JS 有类型(比如,number/string 等),但是 JS 不会检查变量的类型是否发生变化,而 TS 会检查
TypeScript 类型系统的主要优势:可以显示标记出代码中的意外行为,从而降低了发生错误的可能性
TS 中的常用基础类型细分为两类:
- JS 已有类型
-
- 原始类型:number/string/boolean/null/undefined/symbol
- 对象类型:object(包括,数组、对象、函数等对象)
- TS 新增类型
-
- 联合类型、自定义类型(类型别名)、接口、元组、字面量类型、枚举、void、any 等
类型声明
- 语法:
let 变量: 类型;
let 变量: 类型 = 值;
function fn(参数: 类型, 参数: 类型): 类型{
...
}
原始类型(基本类型)
| 类型 | 例子 | 描述 |
|---|---|---|
| number | 1, -33, 2.5 | 任意数字 |
| string | 'hi', "hi", hi | 任意字符串 |
| boolean | true、false | 布尔值true或false |
| 字面量 | 其本身 | 限制变量的值就是该字面量的值 |
| any | * | 任意类型 |
| unknown | * | 类型安全的any |
| void | 空值(undefined) | 没有值(或undefined) |
| never | 没有值 | 不能是任何值 |
number
let a:number;
a = 10;
// a = 'hello'; 报错
let decimal: number = 6;
let hex: number = 0xf00d;
let binary: number = 0b1010;
let octal: number = 0o744;
let big: bigint = 100n;
boolean
let c:boolean = true;
// 赋值的时候就确定类型
let d = false;
// d = 123; 报错
string
let color: string = "blue";
color = 'red';
let fullName: string = `Bob Bobbington`;
let age: number = 37;
let sentence: string = `Hello, my name is ${fullName}.
I'll be ${age + 1} years old next month.`;
字面量
使用字面量去指定变量的类型,通过字面量可以确定变量的取值范围
let color: 'red' | 'blue' | 'black';
let num: 1 | 2 | 3 | 4 | 5;
let e:10;
e = 10;
// e = 11; 报错
字面推断
使用对象初始化变量时,TypeScript 假定该对象的属性可能会在以后更改值
declare function handleRequest(url: string, method: "GET" | "POST"): void;
const req = { url: "https://example.com", method: "GET" };
// 报错,` string `类型的参数不能赋值给` "GET" | "POST" `类型的参数
handleRequest(req.url, req.method);
在这里,req.method 被推断为 string,而不是 GET。因为可以在 req 的创建和 handleRequest 的调用之间评估代码,这可以将一个新的字符串(如 GUESS分配给 req.method),TypeScript 认为此代码有错误,有两种方法解决这个问题:
- 通过在任一位置添加类型断言来更改推断:
// 方式一,让 req.method 始终具有字面量类型 "GET"
const req = { url: "https://example.com", method: "GET" as "GET" };
// 方式二,由于其他原因明确知道 req.method 的值为 "GET"
handleRequest(req.url, req.method as "GET");
- 可以使用
as const将整个对象转换为类型字面:
const req = { url: "https://example.com", method: "GET" } as const;
handleRequest(req.url, req.method);
as const 后缀的作用类似于 const,但用于类型系统,确保为所有属性分配字面类型,而不是更通用的版本,如 string 或 number
any
- 表示任意类型,关闭类型检测
- 如果不指定类型,ts自动判断类型为any
- 编译器标志 noImplicitAny: 对任何类型隐式推断为 any 的变量触发错误
let g:any;
g=10;
g=true;
g="hello"
unknown
表示未知类型的值(类型安全的any,不能赋值给其他变量)
let aa: unknown;
aa = 10;
aa = "hello";
aa = true;
let bb:string;
let cc:any;
// 如果一个变量的类型为any,这个变量可以赋值给其他任意变量
bb = cc; // 正常
// 但类型为 unknown 不能赋值给其他任意变量
// bb = aa; // 报错
if(typeof aa === "string"){
bb = aa;
}
// 类型断言,用来告诉解析器变量的实际类型
bb = aa as string;
// 或者
bb = <string>aa;
void
表示空,以函数为例,表示没有返回值的函数
function fn():void{
// return;
// return null;
return undefined;
// return 123; 报错
}
never
表示永远不会返回结果,一般用于抛出异常的函数
function fn2():never{
throw new Error("报错了!");
}
bigint
用于非常大的整数
const oneHundred: bigint = BigInt(100);
const anotherHundred: bigint = 100n;
symbol
全局唯一引用
const firstName = Symbol("name");
const secondName = Symbol("name");
if (firstName === secondName) {
This comparison appears to be unintentional because the types 'typeof firstName' and 'typeof secondName' have no overlap.
// Can't ever happen
}
对象类型
| object | {name:'孙悟空'} | 任意的JS对象 |
|---|---|---|
| array | [1,2,3] | 任意JS数组 |
| tuple | [4,5] | 元素,TS新增类型,固定长度数组 |
| enum | enum{A, B} | 枚举,TS中新增类型 |
object
// object表示一个对象
let aaa:object;
aaa = {};
aaa = function(){}
// 设置函数结构的类型声明
let ddd:(a:number, b:number)=>number;
ddd = function(n1:number, n2:number):number{
return n1 + n2;
}
array
let list: number[] = [1, 2, 3];
let list: Array<number> = [1, 2, 3];
// string[] 表示字符串数组
let eee:string[];
eee = ['a', 'b', 'c'];
// eee = ['1', 2, 3] 报错
let ggg:Array<number>;
ggg = [2, 3]
tuple
元组:固定长度的数组
let h: [string, number];
h = ['hello', 123]
enum
枚举
// 定义一个枚举类
enum Gender{
male = 0,
female = 1
}
let i:{name:string, gender: Gender};
i = {
name: 'dishitian',
gender: Gender.male
}
console.log(i.gender === Gender.male);
--------------------------------------------
enum Color {
Red,
Green,
Blue,
}
let c: Color = Color.Green;
enum Color {
Red = 1,
Green,
Blue,
}
let c: Color = Color.Green;
enum Color {
Red = 1,
Green = 2,
Blue = 4,
}
let c: Color = Color.Green;
函数
允许指定函数的输入和输出值的类型
function get(name: string): number {
console.log(name);
return 26;
}
// 返回 Promise 的函数
async function getFavoriteNumber(): Promise<number> {
return 26;
}