# 一、什么是TypeScript
- TypeScript 由微软开发,是基于 JavaScript 的⼀个扩展语⾔。
- TypeScript 包含了 JavaScript 的所有内容,即:TypeScript是 JavaScript 的超集
- TypeScript 增加了:静态类型检查、接口、泛型等很多现代开发特性,更适合大型项目 的开发。
- TypeScript 需要编译为 JavaScript ,然后交给浏览器或其他 JavaScript 运行环境执行。
# 相对于JavaScript解决了什么?
- 不清楚的数据类型
let welcome = 'hello'
welcome() // 此⾏报错:TypeError: welcome is not a function
- 有漏洞的逻辑
const str = Date.now() % 2 ? '奇数' : '偶数'
if (str !== '奇数') {
alert('hello')
} else if (str === '偶数') {
alert('world')
}
- 访问不存在的属性
const obj = { width: 10, height: 15 };
const area = obj.width * obj.heigth;
😞 4. 低级的拼写错误
const message = 'hello,world'
message.toUperCase()
😞 5. 静态类型检查
-
在代码运⾏前进⾏检查,发现代码的 错误或不合理之处,减⼩运⾏时出现异常 的⼏率,此种检查叫『静态类型检查』,TypeScript 和核⼼就是『静态类型检查』,简⾔之就是把运⾏时的错误前置。
-
同样的功能,TypeScript 的代码量要⼤于 JavaScript ,但由于 TypeScript 的代码结构更 加清晰,在后期代码的 维护中 TypeScript 却胜于 JavaScript 。
# 二、基础类型及特性
类型 | 描述 | 示例 |
---|---|---|
string |
表示文本数据 | let name: string = "Alice"; |
number |
表示数字,包括整数和浮点数 | let age: number = 30; |
boolean |
表示布尔值 true 或 false |
let isDone: boolean = true; |
array |
表示相同类型的元素数组 | let list: number[] = [1, 2, 3]; |
tuple |
表示已知类型和长度的数组 | let person: [string, number] = ["Alice", 30]; |
enum |
定义一组命名常量 | enum Color { Red, Green, Blue }; |
any |
任意类型,不进行类型检查 | let value: any = 42; |
void |
无返回值(常用于函数) | function log(): void {} |
null |
表示空值 | let empty: null = null; |
undefined |
表示未定义 | let undef: undefined = undefined; |
never |
表示不会有返回值 | function error(): never { throw new Error("error"); } |
object |
表示非原始类型 | let obj: object = { name: "Alice" }; |
union |
联合类型,表示可以是多种类型之一 | `let id: string | |
unknown |
不确定类型,需类型检查后再使用 | let value: unknown = "Hello"; |
关于TypeScript的特别类型
# Any
any 的含义是:任意类型,⼀旦将变量类型限制为 any,那就意味着放弃了对该变量的类型检查,可以赋值给任意类型的变量。
# Unknown
unknown 的含义是:未知类型。会强制开发者在使⽤之前进⾏类型检查,从⽽提供更强的类型安全性。
适⽤于:起初不确定数据的具体类型,要后期才能确定.
对比any
: 读取 any
类型数据的任何属性都不会报错,⽽unknown
正好与之相反
let str1: string
str1 = 'hello'
str1.toUpperCase() // ⽆警告
let str2: any
str2 = 'hello'
str2.toUpperCase() // ⽆警告
let str3: unknown
str3 = 'hello';
str3.toUpperCase() // 警告:“str3” 的类型为“未知”
// 使⽤断⾔强制指定str3 的类型为string
(str3 as string).toUpperCase() // ⽆警告
# Never
never 的含义是:任何值都不是,即:不能有值,例如 undefined 、null、'' 、0都不行
- ⼏乎不⽤
never
去直接限制变量,因为没有意义 - never ⼀般是
typeScript
主动推断出来的 - never 也可⽤于
限制函数的返回值
// 限制throwError 函数不需要有任何 返回值,任何值都不⾏,像undeifned 、null 都不⾏
function throwError(str: string): never {
throw new Error(' 程序异常 退出:' + str)
}
# Void
void 的含义是空,即:函数不返回任何值,调⽤者也不应依赖其返回值进⾏任何操作!
# Undefined
undefined 也是一种空,如果说Void是一种概念,那Undefined就是Void的一种实现。
可以说 undefined 是 void 能接受的⼀种“空”的状态。
也可以理解为: void 包含 undefined。
# Tuple
元组 (Tuple) 是⼀种特殊的数组类型,可以存储固定数量的元素,并且每个元素的类型是已知的且可以不同。
元组⽤于精确描述⼀组值的类型, ? 表示可选元素。
// 第⼀个元素必须是 string 类型,第⼆个元素必须是 number 类型。
let arr1: [string,number]
// 第⼀个元素必须是 number 类型,第⼆个元素是可选的,如果存在,必须是 boolean 类型。
let arr2: [number,boolean?]
// 第⼀个元素必须是 number 类型,后⾯的元素可以是任意数量的 string 类型
let arr3: [number,...string[]]
// 可以赋值
arr1 = ['hello',123]
arr2 = [100,false]
arr2 = [200]
arr3 = [100,'hello','world']
arr3 = [100]
// 不可以赋值,arr1 声明时是 两个 元素,赋值的是三个
arr1 = ['hello',123,false]
# Enum
枚举( enum )可以定义⼀组命名常量,它能增强代码的可读性,也让代码更好维护。
数字枚举
数字枚举⼀种最常⻅的枚举类型,其成员的值会
自动递增
,且数字枚举还具备反向映射
的特点
// 定义⼀个描述【上下 左右】⽅向的枚举Direction
enum Direction {
Up,
Down,
Left,
Right
}
// 打印Direction 会看到如下内容
/* {
0:'Up', 1:'Down', 2:'Left', 3:'Right',
Up:0, Down:1, Left:2, Right:3
}*/
也可以指定枚举成员的初始值,其后的成员值会⾃动递增。
enum Direction {
Up = 6,
Down,
Left,
Right
}
console.log(Direction.Up); // 输出: 6
console.log(Direction.Down); // 输出: 7
字符串枚举
枚举成员的值是字符串,在js即为创建一个对象赋值为一个字符串
enum Direction {
Up = "up",
Down = "down",
Left = "left",
Right = "right"
}
let dir: Direction = Direction.Up;
console.log(dir); // 输出: "up"
一般情况下推荐使用字面类型+联合类型组合的方式,相比枚举,这种方式更加直观、简洁、高效。
# Type
type 可以创建一个类型,常用于
联合类型
与交叉类型
联合类型
联合类型是一种高级类型,表示一个变量可以是不同类型之一
type Status = number | string
type Gender = '男' | '⼥'
function printStatus(status: Status) {
console.log(status);
}function logGender(str:Gender){
console.log(str)
}
printStatus(404); //可以为number
printStatus('200'); //可以为string
logGender('男')
logGender('⼥')
交叉类型
交叉类型(Intersection Types )允许将多个类型合并为⼀个类型。合并后的类型将拥有所有被合并类型的成员。交叉类型通常⽤于对象类型。
// 定义两个类型
// ⾯积
type Area = {
height: number; // ⾼
width: number; // 宽
};
// 地址
type Address = {
num: number; // 楼号
cell: number; // 单元号
room: string; // 房间号
};
// 定义类型House ,且 House 是Area 和Address 组成的交叉类型
type House = Area & Address;
const house: House = {
height: 180, width: 75, num: 6, cell: 3, room: '702'
};//两个类型内的变量都需要
# 泛型
泛型(Generics)是一种编程语言特性,允许在定义函数、类、接口等时使用占位符来表示类型,而不是具体的类型。
//泛型函数
function logData<T>(data: T): T {
console.log(data)
return data
}
logData<number>(100)
logData<string>('hello')
----------------------------
//泛型可以有多个
function logData<T, U>(data1: T, data2: U): T | U {
console.log(data1,data2)
return Date.now() % 2 ? data1 : data2 //获取当前时间奇数返回data1,偶数返回data2
}
logData<number, string>(100, 'hello')
logData<string, boolean>('ok', false)
----------------------------
//泛型接口
interface PersonInterface<T> {
name: string, age: number, extraInfo: T
}
let p1: PersonInterface<string> ;
let p2: PersonInterface<number> ;
p1 = { name: '张三', age: 18, extraInfo: '⼀个好⼈' }
p2 = { name: '李四', age: 18, extraInfo: 250 }
----------------------------
//泛型约束
interface LengthInterface {length: number }
// 约束规则是:传⼊的类型T必须具有 length 属性
function logPerson<T extends LengthInterface>(data: T): void {
console.log(data.length)
}
logPerson<string>('hello')
// 报错:因为number 不具备length 属性
// logPerson<number>(100)
----------------------------
//泛型类
class Person<T> {
constructor(
public name: string,
public age: number,
public extraInfo: T) { }
speak() {
console.log(` 我叫${this.name} 今年${this.age} 岁了`) ;
console.log(this.extraInfo) }
}
// 测试代码1
const p1 = new Person<number>("tom", 30, 250);
// 测试代码2
type JobInfo = {
title: string; company: string;
}
const p2 = new Person<JobInfo>("tom", 30, {
title: '研发总监',
company: '666科技公司'
});
# 三、函数与变量声明
# 变量声明
声明变量的几种情况:
- 有类型无初始值: 初始值为undefined
- 无类型无初始值:类型为:any,初始值为undefined
- 无类型有初始值:类型为初始值的类型
let 变量名: 数据类型 = ...;
const 变量名: 数据类型 = ...; // const声明后变量的值不能被重新赋值。
// 可以使用 Union类型,指定类型中的其中一种
let u: 类型|类型|类型 = ...
# 函数声明
function sayHello(name?:string){
//判断name是否有值,如果无值则给一个默认值
name=name?name:陌生人
}
sayHello('jack')//输出 jack
sayHello()//输出 陌生人
//还可以在参数后面赋值,表示参数默认值
function sayHello(name: string = '...'){
//如果无值则使用默认值
}
# 四、循环与条件控制
# 循环
TS为一些内置类型提供了快捷迭代
let names :string[]=[...]
//for in 送代器,遍历得到数组角标
for(const i in names){
...
}
//for of 迭代器,直接得到元素
for(const name of names){
...
}
# 条件控制
Typescript支持基于 if-else & switch的条件控制
if(num === 0){
...
}
// TS中 空字符串,0,null,undefined 为false,其它值为true
在 TS中建议使用 === 的比较运算符
# 声明文件
TypeScript 作为 JavaScript 的超集,在开发过程中不可避免要引用其他第三方的 JavaScript 的库,为了解决这个问题,需要将这些库里的函数和方法体去掉后只保留导出类型声明,而产生了一个描述 JavaScript 库和模块信息的声明文件。通过引用这个声明文件,就可以借用 TypeScript 的各种特性来使用库文件了
//demo.js
// 模块导出 关键字 export
export function add(a, b) {
return a + b;
}
export function mul(a, b) {
return a * b;
}
//xxx.d.ts
// 使用 declare 关键字定义它的类型
declare function add(a: number, b: number): number;
declare function mul(a: number, b: number): number;
export { add, mul };
--------------------------
// example.ts 另一个文件
import { add, mul } from "./demo.js";
const x = add(2, 3);
// x 类型为 number
const y = mul(4, 5);
// y 类型为 number
console.log(x,y)
# 声明文件
声明文件以 .d.ts 为后缀,例如:
xxx.d.ts
声明文件或模块的语法格式如下:
declare module Module_Name {
}
TypeScript 引入声明文件语法格式:
/// <reference path = " runoob.d.ts" />
当然,很多流行的第三方库的声明文件不需要我们定义了,比如 jQuery 已经有人帮我们定义好了:jQuery in DefinitelyTyped。