# 一、什么是TypeScript

  1. TypeScript 由微软开发,是基于 JavaScript 的⼀个扩展语⾔。
  2. TypeScript 包含了 JavaScript 的所有内容,即:TypeScript是 JavaScript 的超集
  3. TypeScript 增加了:静态类型检查、接口、泛型等很多现代开发特性,更适合大型项目 的开发。
  4. TypeScript 需要编译为 JavaScript ,然后交给浏览器或其他 JavaScript 运行环境执行。

# 相对于JavaScript解决了什么?

  1. 不清楚的数据类型
let welcome = 'hello' 
welcome() // 此⾏报错:TypeError: welcome is not a function 
  1. 有漏洞的逻辑
const str = Date.now() % 2 ? '奇数' : '偶数'
if (str !== '奇数') {
    alert('hello') 
} else if (str === '偶数') {
    alert('world') 
}
  1. 访问不存在的属性
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 表示布尔值 truefalse 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都不行

  1. ⼏乎不⽤never去直接限制变量,因为没有意义
  2. never ⼀般是typeScript主动推断出来的
  3. 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=namename陌生人
}
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