0.Ts基础
0.0 【如何初始化 tsconfig.json文件】
通过在命令行终端输入
tsc --init可以快速初始化 一个名叫tsconfig.json的Ts配置文件0.1【如何监听 ts 文件的变化自动生成对应的 js 文件】
通过在命令行终端输入
tsc --watch可以监听当前.ts的改变,自动生成向对应的.js文件0.2【ts 中的基本类型】
string、number、boolean、Array、any0.4【ts 中的类型注释】
let myAge: number = 20 // :number 便是变量 myAge 的类型注释let myName = 'Youwei' // 也可不用显示的指定其变量的类型注释,TypeSCript 会根据值类型自动推断
0.5【ts 中函数的类型注释】
``typescript function getName(name: string): string{ console.log(my name is ${name}`) return name }
// 在上面函数中,括号内参数可以也可以书写类型注释,括号后的 :string 表示该函数返回值的类型注释
<a name="szr7s"></a>#### 0.6【上下文类型】```typescriptconst food = ['肉夹馍','凉皮','冰峰']food.forEach((item)=>{item.toUpperCase()})// 观察上面函数,可以发现,函数的参数 item 并没有指定类型注释,但依然可以使用字符串才有的方法// 这是因为 TypeSCript 会自动根据 food 参数的类型与 forEach 函数的上下文类型中,自动推断出参数 item 的类型
0.7【对象参数类型】
function printCoord(PT: {X: number, Y: number}) {console.log(`坐标X的值为:${PT.X}`);console.log(`坐标Y的值为:${PT.Y}`);}printCoord({X:300, Y:400})//可以将函数的参数的类型注释指定为一个对象传入
0.8【可选参数】
function getPersonName(person: { name: string, age?: number }) {console.log(`姓名为:${person.name}`);console.log(`年龄为:${person.age}`);}getPersonName({name: '柳白猿'})// 上面函数的参数 age?: number 表示该参数是一个可传可不传的参数// 当我们调用 getPersonName 函数时不传入 age 参数也不会触发 TypeScript 的类型检查
0.9【联合类型】
联合类型可以让我们变量或参数类型变得宽泛,但如果需要使用该变量或者参数时,就一定要让其满足多种类型的具备的方法或属性
// id:number | string 表示联合类型,即此时 id 的类型可以为 number类型 或者 string类型let id: number | string = '001x'id = '100' // 正确id = 100 // 正确id = {uid: 100} // 错误// --------------------------------------------------------------------------------//function getName(name: string[] | string){// 当我们给 name 参数直接使用 数组的方法时,会报错。因为 name 不一定是数组类型,有可能只是一个 string 类型// name.join() 直接使用会报错// 此时我们可以使用 if 语句进行判断,来达到目的if(Array.isArray(name)){return name.join('浩克')}else{return name.toUpperCase()}}getName(['mark42', '奇异博士', 'Tony'])getName('绯红女巫')getName(20) // 报错// 函数 getName 方法接收一个 name 参数,而 name 参数的类型可以是一个 string类型的数组,或者 string
0.10【类型别名】
使用 type 关键字来定义类型别名
// 定义变量 ponit 为对象类型type point = {X: number,Y: number}function getPoint(point: point){console.log(`当前X位置为${point.X}`);console.log(`当前Y位置为${point.Y}`);}getPoint({X: 500, Y: 100}) // 正确getPoint(Y:100) // 报错// 定义变量 ID 的类型为 number类型的数组或 string类型type ID = number[] | stringfunction getId(id: ID) {return id.slice(0,2)}getId([100,200,300]) // 正确getId('100') // 正确getId({id: '100'}) // 报错// 定义变量 returnType 的类型为 string 或 number类型type returnType = string | numbertype value = number | stringfunction setSumVal(value): returnType {return value}setSumVal(20) // 正确setSumVal('1000') // 正确setSumVal([100,200,'300']) // 报错
0.11【接口 interface】
使用 interface 关键字来定义接口
interface IPonit{X: number,Y: number}function getPoint(point: point){console.log(`当前X位置为${point.X}`);console.log(`当前Y位置为${point.Y}`);}getPoint({X: 500, Y: 100})
0.12【接口与类型别名的区别】
- 接口使用
interface关键字定义,类型别名使用type关键字定义,两者都是定义类型注释 - 类型别名
type使用&来扩展新的属性,interface接口则通过extends继承老接口属性,来扩展新属性 同一个接口可以支持重复定义,并添加新的属性,但是同一个类型别名不支持重复定义
0.12.1【接口的扩展】
接口的扩展可以使用
extends关键字,让新接口在不修改老接口的情况下,添加新的属性 ```typescript interface IPerson{ name: string, age: number }
// 此时的 ISkill 接口中除了有 skill 属性还有,继承自 IPerson 接口的 name 属性与 age 属性 interface ISkill extends IPerson{ skill: string }
// 此时的变量 Tony 的类型必须同时满足 IPerson 与 ISkill 两个接口的定义 const Tony: ISkill = { name: ‘Tony’, age: 30, skill: ‘钞能力’ } // 在上面的栗子中可以看到, ISkill 接口通过 extends 继承了 IPerson 接口,并且定义了自己的新属性 // 在使用 ISkill 作为变量 Tony 的类型注释时就必须要满足 IPerson 与 ISkill 两种接口的定义
<a name="ze8XM"></a>##### 0.12.2【类型别名的扩展】- 类型别名通过 `&` 来基于旧的类型别名,扩展新的属性```typescripttype IAnimal = {name: stringage: number}// 此时的 IPanda 中不仅有 hobby,还有扩展自 IAnimal 的 name 与 age 属性type IPanda = IAnimal & {hobby: string}// 变量 pandaInfo 必须同时满足 类型别名 IAnimal 与 IPanda 中定义的属性const pandaInfo: IPanda = {name: '大宝',age: 3,hobby: '睡觉'}// 上面的栗子,IPanda 通过 & 基于 IAnimal 扩展了自己新的属性 hobby// 在使用时,变量 pandaInfo 使用了类型注解 IPanda,就需要同时满足 IAnimal 与 IPanda 的定义
0.12.3【重复定义】
interface IPerson{name: string}interface IPerson{age: number}interface IPerson{hobby: string}const person: IPerson = {name: 'Tony',age: 30,hobby: 'honey'}// 以上的接口 IPerson 被重复定义多次,并不会报错// 并且在使用 IPerson 作为类型注解时,需要满足接口的所有定义// -----------------------------------------------------------------------------//type IAnimal = {name: string}type IAnimal = {age: string}type IAnimal = {skill: string}类型别名不支持重复定义,会报错:标识符“IAnimal”重复
0.13【断言】
- 使用
as可以更具体的指定某一属性或变量的类型,类型断言由编译器删除,不会影响代码运行时的行为,所以也没有与as相关的运行时检查 ```typescript const canvas1 = document.getElementById(‘myCanvas’) as HTMLCanvasElement
const canvas2 =
// 通过上面的栗子,获取了id 名为 myCanvas 的元素,但 TypeScript 只会返回某种类型的 HTMLElement // 但是并不知道具体是哪一种类型的 HTMLElement 元素,这时候可以使用 as 语法,指定一个明确的类型
<a name="r4H8S"></a>#### 0.14【文字类型】- 可以使用 文本 或者 数字 作为变量或参数类型<a name="H70YG"></a>##### 0.14.1【字符串文字类型】```typescriptlet personName: 'Tony' = 'Tony'personName = 'zs' // 报错:不能将类型“"zs"”分配给类型“"Tony"”// 上面的栗子中,将字符串 'Tony' 设置为变量 personName 的类型注解,当赋值不是 字符串的 'Tony' 是便会报错//----------------------------------------------------------------------------------------//// 一般用配合联合类型使用,文字联合类型,达到一个更具体的概念function getLocation(name: string, location: 'left' | 'top' | 'right'){console.log(`名称是${name}, 位置在${location}`);}getLocation('Tony', 'right') // 正确getLocation('Hulk', 'top') // 正确getLocation('zs', '左上角') // 报错:类型“"bottom"”的参数不能赋给类型“"left" | "top" | "right"”的参数// getLocation 函数的第二个参数 location 此时只允许传入 'left' | 'top' | 'right',这几种字符串// 相当于限制死了 location 参数的值
0.14.2【数值文字类型】
// 数值文字类型与字符串文字类型类似function compare(a: string, b: string): 1 | 0 | -1{// return a === b ? 0 : a > b ? 1 : 2 报错:不能将类型“2”分配给类型“0 | 1 | -1”return a === b ? 0 : a > b ? 1 : -1}// 在上面的栗子中,已经规定了函数的返回值必须是 1 | 0 | -1// 如果函数 compare 的返回值不是 1 | 0 | -1 其中的一种,便会报错
0.14.3【文字类型与其他类型的结合】
interface IOption {width: number}function setValue(value: IOption | 'auto'){return value}setValue({width: 200})setValue('auto')setValue(30) // 报错:类型“30”的参数不能赋给类型“IOption | "auto"”的参数
0.14.4【布尔文字类型】
let flag1: true = truelet flag2: false = falseflag1 = false // 报错:不能将类型“false”分配给类型“true”flag2 = true // 报错:不能将类型“true”分配给类型“false”// 上面的栗子:相当于对 flag1 和 flag2 设置了一个固定的布尔值类型注释,重新赋值会报错
0.14.5【文字推理】
let obj = {value: 0}obj.value = 0obj.value = '0' // 报错:不能将类型“string”分配给类型“number”// TypeScript 基于上下文,帮我们推断出了 value 的类型为 number,// 当赋值数字类型的 0 时可以成功,赋值为字符串类型 '0' 即报错// -----------------------------------------------------------------------------------//const request = {url: 'http:xxxxxx.com',method: 'GET'}function getDataList(url: string, method: 'GET'| 'POST'){return `url是:${url}, 请求方法是${method}`}getDataList(request.url, request.method) // 报错:类型“string”的参数不能赋给类型“"GET" | "POST"”的参数// 上面函数栗子:参数 method 的类型只能是 'GET'| 'POST',其实传入的值是对的// 但是 TypeScript 帮我们自动推断 request.method 的值为 string 类型,导致类型判断失败报错// 解决方法:// 1. getDataList(request.url, request.method as 'GET') // 正确,使用类型断言解决// 2. const request = {// url: 'http:xxxxxx.com',// method: 'GET'// } as const 给整个 request 对象,断言为 const 将类型固定
0.15【null和undefined类型】
let Y: undefined = undefinedlet X: null = nullfunction getName(x? number | null){console.log(x!.toFixed()) // 使用非空断言}// 在上述的栗子中,对变量 x 使用 !,表示非空断言,即 x 的值一定存在,将 null 与 undefined 排除在外
0.16【枚举类型】
- 枚举类型通过
enum关键字来定义,后面跟一个枚举的名字与类型定义 - 默认情况下,枚举成员是基于 0 开始递增,当显式的设置了类型类型的值,则会根据值,返回相应的结果 ```typescript enum Food { noodles , Hamburger, rice, }
Food.noodles // 0 Food.Hamburger // 1 Food.rice // 2 // ————————————————————————————————— enum Fruits { apple = 1, // 显式的设置了枚举类型的值 banana, strawberry, grape, }
Fruits.apple // 1 Fruits.banana // 2 Fruits.strawberry // 3 ….
<a name="Zns8q"></a>#### 0.17【类型缩小】- `TypeScript` 类型收窄就是从宽类型转换成窄类型的过程,类型收窄常用于处理联合类型变量的场景。<a name="USweb"></a>##### 0.17.1【typeof 类型守卫】- `typeof`可以获取 `Ts` 代码在执行时,有关值最基本的类型信息```typescriptfunction printAll(strs: string | string[] | null) {if (Array.isArray(strs) ) {// strs 为数组时 TODOfor (const value of strs){}} else if (typeof strs === 'string') {// strs 为字符串时 TODO} else {// 为 null 时 TODO}}// 在上面栗子中,首先通过 Array.isArray() 方法判断 strs 是否为一个数组 strs 为数组时命中// 接下来通过 typeof 判断 strs 的值是否为字符串,当 strs 为字符串命中// 若以上都未命中,则 strs 的值为 null
0.17.2【真值缩小】
通过 条件、&&、||、if语句、布尔否定( ! ) 组成一个布尔表达式
function multiplyAll(values: number[] | undefined, factor: number){if(!values){return values}else{return values.map(() => {return x * factor})}}multiplyAll([8.9],2)// 通过 ! 取反 values 变量,组成一个布尔表达式,若逻辑命中做一些事情,未命中进行其他操作
0.17.3【等值缩小】
===、!==、==、!=来处理等值检查,实现类型缩小function example(x: string | number, y: string | boolean){if( x === y){x.toUpperCase()y.toUpperCase()}else{// TODO...}}// 上面的栗子中,由于函数参数 x 和 y 共同存有类型注释 string 所以 if 会成立
0.17.4【in操作符缩小 】
使用
in运算符,用来确定某一对象是否有某个名称的属性,以此缩小潜在类型的范围

type Fish = { swim: () => void }type Bird = { fly: () => void }function move(animal: Fish | Bird) {if ('swim' in animal) {return animal.swim()}return animal.fly()}// 在上面的栗子中:animal 的类型注释是 Fish 与 Bird 的联合类型// 因此在 if 语句的判断中 'swim' 是存在于 animal 中的
0.17.5【分配缩小】
let x = Math.random() < 0.5 ? 10 : 'hello world'// 现在变量 x 现在相当于拥有 number | string 的联合类型,let x :number | stringlet x = 1000 // 正确 满足 let x :number 类型let x = 'Yooooo' // 正确 满足 let x :string 类型let x = [] // 报错let x = {} // 报错
0.18【never类型】
never类型表示不应该存在的状态never类型可以分配给每个类型,但是除never本身以外,没有任何类型可以分配给never类型let x: neverx = 'hellow', // 报错:不能将类型“string”分配给类型“never”x = 20 // 报错:不能将类型“number”分配给类型“never”
0.19【函数】
0.19.1【函数类型表达式】
fn: (a:string) => void// 上面的栗子就是一段函数表达式类型// fn 函数后面有点类似箭头函数的样子的便是 fn 函数的类型
0.19.2【函数重载】
函数重载或方法重载,是使用相同名称和不同参数、数量或类型创建多个方法的一种能力
// 为 add 函数提供了多个函数类型定义,从⽽实现函数的重载type Combinable = string | numberfunction add(a: number, b: number): number;function add(a: string, b: string): string;function add(a: string, b: number): string;function add(a: Combinable, b: Combinable) {// type Combinable = string | number;if (typeof a === 'string' || typeof b === 'string') {return a.toString() + b.toString();}return a + b;}
