DAY1
为何TS?
-
JS是一门优秀的语言:web端-js,移动端-ReactNative/Weex/Uniapp,小程序端-js,桌面端-Electron,服务器端-js
-
JS痛点:在类型检测上没有进展
-
类型检测:错误出现越早越好
- 静态检测:写代码的时候发现错误-IDE
- 代码编译期间:类型检测--JS难以做到
- 尽量避免在代码运行期间、开发阶段、测试阶段发现错误-越早发现越好
-
JS没有对传入参数进行任何限制,只有等到运行期间才发现错误,影响后续代码继续执行
-
JS未考虑类型约束,造成前端开发人员关于类型思维的缺失
-
对于大型项目,宽松的类型约束会带来很多的安全隐患,多人员开发时,没有良好的类型约定
-
什么是TS?
定义
静态类型检查器:TypeScript 在执行之前,基于 值的类型 检查程序是否有错误。它是 静态类型检查器。
JavaScript 的类型化超集: TS对JS拥有的特性全部支持,且支持ES标准;语言层面上,不仅增加了类型约束,包括了一些语法的扩展;TS最终会被编译位JS代码(tsc/babel)
运行环境
方式一:
通过tsc编译TS到JS代码--webpack,配置本地的TS编译环境和开启一个本地服务,可直接运行到浏览器上
npm install typescript -g
方式二:在浏览器或者Node环境下运行JS代码--ts-node库,为TS的运行提供执行环境
npm install ts-node -g
npm install tslib @types/node -g
运行:ts-node 文件名.ts
TS变量声明
变量声明:指定标识符的类型
完整声明格式:var/let/const 标识符: 数据类型 = 赋值 注意:数据类型是小写
例如:let message: string = 'hello' (string为TS中定义的字符串类型,String为js中字符串的包装类)
声明类型后TS就会进行类型检测,声明的类型称为类型注解
声明变量的关键字
同es6:var/let/const定义
变量的类型推断
一个变量第一次赋值时,会根据后面的复制内容的类型,来推断变量的类型
-
TS数据类型
JavaScript 中已经有一些基本类型可用:
boolean、bigint、null、number、string、symbol和undefined,它们都可以在接口中使用。TypeScript 将此列表扩展为更多的内容,例如any(允许任何类型)、[unknown](https://www.typescriptlang.org/play#example/unknown-and-never)(确保使用此类型的人声明类型是什么)、[never](https://www.typescriptlang.org/play#example/unknown-and-never)(这种类型不可能发生)和void(返回undefined或没有返回值的函数)。构建类型有两种语法: 接口和类型。 常用
interface。当需要特定功能时使用type。
支持JS数据类型
// 数字 布尔 字符串类型 ---这些用法和JS一样
let num: number = 123.3
let flag: boolean = true
const name = 'lgl'
// 数组类型 1.数组中存放的类型[] 2.Array<数组中存放的类型> (泛型写法)
let names: string[] = ["aaa", "bbb", "ccc"]
let nums: Array<number> = [111, 222, 333.1];
// 对象类型
//1.直接object--info.name,info.age等报错,不能获取数据和设置数据
const info: object = {
name: "xdh",
age: 18,
};
//2.使用interface type等,或者写全(若补充不全也报错)
let info:{
name:string,
age:number
} = {
name: "xdh",
age: 18,
}
// null undefined类型
const n1: null = null;
const n2: undefined = undefined;
// Symbol类型:Symbol函数返回的是不同值
const title1:symbol = Symbol("title")
const title2:symbol = Symbol('title')
const info = {
[title1]: "程序员",
[title2]: "老师"
}
//函数类型 定义参数类型,定义返回类型
// 1.定义对象类型
type LyricType = {
time: number
text: string
}
// 2.歌词解析工具 传入参数lyric为string,返回一个数组,每一个项是对象
function parseLyric(lyric: string): LyricType[] {
const lyrics: LyricType[] = []
lyrics.push({ time: 1111, text: "天空想要下雨" })
return lyrics
}
const lyricInfos = parseLyric("fdafdafdafa")
for (const item of lyricInfos) {
console.log(item.time, item.text)
}
//可选类型:对象类型也可以指定哪些属性可选,在属性后面添加?
// 可以对象类型和函数类型结合使用
type PointType = {
x: number
y: number
z?: number
}
function printCoordinate(point: PointType) {
console.log("x坐标:", point.x)
console.log("y坐标:", point.y)
}
TS特有特性
-
any类型
在 TypeScript 中,
any类型可以被用来表示任何类型,包括原始类型、对象类型以及函数类型。使用
any类型时,编译器将不会对该类型进行任何类型检查,允许在编译时和运行时对其进行任何操作,因此被称为“逃逸舱”类型。应该在必要的时候才使用
any类型,尽可能使用更具体的类型来表示代码中的数据类型。在使用any类型时,可以通过类型断言等方式尽可能减少其使用范围,并在运行时进行必要的类型检查以保证代码的健壮性。// any类型就表示不限制标识符的任意类型, 并且可以在该标识符上面进行任意的操作(在TypeScript中回到JavaScript中) let id: any = "aaaa" id = "bbbb" id = 123 console.log(id.length) id = { name: "why", level: 99 } // 定义数组 const infos: any[] = ["abc", 123, {}, []] -
unknown类型
unknown类型是TS中比较特殊的一种类型,用于描述类型不确定的变量和
any类型类似,但unknown类型的值上做任何事情都不合法let foo: unknown = "aaa" foo = 123 // unknown类型默认情况下在上面进行任意的操作都是非法的 // 要求必须进行类型的校验(缩小), 才能根据缩小之后的类型, 进行对应的操作 if (typeof foo === "string") { // 类型缩小 console.log(foo.length, foo.split(" ")) } export {} -
void类型
void通常用来指定一个函数是没有返回值的,那么它的返回值就是void类型
当基于上下文的类型推导推导出返回类型为void的时候,并不会强制函数一定不能返回内容
// 1.在TS中如果一个函数没有任何的返回值, 那么返回值的类型就是void类型(可以显式指定,也可以不写) // 2.如果返回值是void类型, 那么我们也可以返回undefined(TS编译器允许这样做而已) function sum(num1: number, num2: number): void { console.log(num1 + num2) // return 123 错误的做法 } // 应用场景: 用来指定函数类型的返回值是void type LyricInfoType = { time: number, text: string } // parseLyric函数的数据类型: (lyric: string) => LyricInfoType[] function parseLyric(lyric: string): LyricInfoType[] { const lyricInfos: LyricInfoType[] = [] // 解析 return lyricInfos } // parseLyric => 函数/对象 //foo的类型是FooType->函数类型,没有返回值 type FooType = () => void const foo: FooType = () => {} // 举个例子:(涉及函数的类型问题, 后续还会详细讲解) // 1.定义要求传入的函数的类型 type ExecFnType = (...args: any[]) => void // 2.定义一个函数, 并且接收的参数也是一个函数, 而且这个函数的类型必须是ExecFnType function delayExecFn(fn: ExecFnType) { setTimeout(() => { fn("why", 18) }, 1000); } // 3.执行上面函数, 并且传入一个匿名函数 delayExecFn((name, age) => { console.log(name, age) }) export {} -
never类型
never表示永远不会发生值得类型,比如一个函数:如果一个函数中是一个死循环或者一个异常,这个函数不会返回东西,此时可以用
never类型// 一. 实际开发中只有进行类型推导时, 可能会自动推导出来是never类型, 但是很少使用它 // 1.一个函数是死循环 // function foo(): never { // // while(true) { // // console.log("-----") // // } // throw new Error("1233") // } // foo() // 2.解析歌词的工具 function parseLyric() { return [] } // 二. 封装框架/工具库的时候可以使用一下never // 其他时候在扩展工具的时候, 对于一些没有处理的case, 可以直接报错 function handleMessage(message: string | number | boolean) { switch (typeof message) { case "string": console.log(message.length) break case "number": console.log(message) break case "boolean": console.log(Number(message)) break default: const check: never = message } } handleMessage("aaaa") handleMessage(1234) // 另外同事调用这个函数 handleMessage(true) export {} -
tuple类型
元组类型和数组的区别:
数组中通常建议存放相同类型的元素,不同类型的元素不推荐放在数组中。
元组中每个元素都有自己特性的类型,根据索引值获取到的值可以确定对应的类型;
tuple通常可以作为返回的值,在使用的时候会非常方便。(例如useState的hooks)// 保存我的个人信息: why 18 1.88 // 1.使用数组类型 // 不合适: 数组中最好存放相同的数据类型, 获取值之后不能明确的知道对应的数据类型 const info1: any[] = ["why", 18, 1.88] const value = info1[2] console.log() // 2.使用对象类型(最多) const info2 = { name: "why", age: 18, height: 1.88 } // 3.使用元组类型 // 元组数据结构中可以存放不同的数据类型, 取出来的item也是有明确的类型 const info3: [string, number, number] = ["why", 18, 1.88] const value2 = info3[2] // 在函数中使用元组类型是最多的(函数的返回值) function useState(initialState: number): [number, (newValue: number) => void] { let stateValue = initialState function setValue(newValue: number) { stateValue = newValue } return [stateValue, setValue] } const [count, setCount] = useState(10) console.log(count) setCount(100) export {} -
联合类型和交叉类型
TS允许我们使用多种运算符,从现有类型中构建新类型
-
联合类型
Union Type -
联合类型是由两种或者多种其他类型组成的类型
-
表示可以是这些类型中的任何一个值
-
联合类型中的每一个类型被称之为联合成员
-
使用的时候要进行类型缩小
// 1.联合类型的基本使用 // let foo: number | string = "abc" // foo = 123 // // 使用的时候要特别的小心 // if (typeof foo === "string") { // console.log(foo.length) // } // 2.举个栗子: 打印id function printID(id: number | string) { console.log("您的ID:", id) // 类型缩小 if (typeof id === "string") { console.log(id.length) } else { console.log(id) } } printID("abc") printID(123) -
-
交叉类型
- 交叉类型标识需要满足多个类型的条件
- 交叉类型使用
&符号 - 交叉类型其实是一个never类型,在开发中,通常是对对象类型进行交叉的
// 交叉类型: 两种(多种)类型要同时满足 type NewType = number & string // 没有意义 interface IKun { name: string age: number } interface ICoder { name: string coding: () => void } type InfoType = IKun & ICoder const info: InfoType = { name: "why", age: 18, coding: function() { console.log("coding") } }