TypeScript基础
目录
基本使用
使用场景
枚举类型
any 类型
类型断言
TypeScript 泛型
泛型在函数上的应用
泛型在接口上的应用
泛型在类型别名上的应用
字面量类型:将字面量当做一个类型去使用
基本使用
思考以下代码,两个变量的类型分别是什么?
let str1 = 'hello ts'
const str2 = 'hello ts'
-
通过 TS 类型推断机制,可以得到答案:
-
变量 str1 的类型为:string
-
变量 str2 的类型为:'hello ts'
-
-
解释:
-
str1 是一个变量(let),它的值可以改变,可以是任意字符串,所以类型为 string
-
str2 是一个常量(const),它的值不能改变,只能是 'hello ts',所以,它的类型为 'hello ts'
-
-
注意:此处的 'Hello TS',就是一个字面量类型
-
任意的 JS 字面量(比如,数字、字符串、布尔值、数组、对象、函数等)都可以作为类型使用
-
字面量:
20
'abc'
false
[]
{ name: 'jack' }
function() {}
-
使用场景
使用场景:字面量类型配合联合类型一起使用,表示一组明确的可选值
优点:使用字面量类型更加精确、严谨
-
示例 1:性别的取值,只能是男或女其中的一个
type GenderType = '男' | '女'
// 赋值时,会有类型提示
let gender: GenderType = '男'
示例 2:在贪吃蛇游戏中,游戏的方向的可选值只能是上、下、左、右中的任意一个
// 使用自定义类型:
type DirectionType = 'up' | 'down' | 'left' | 'right'
function changeDirection(direction: DirectionType) {
console.log(direction)
}
// 调用函数时,会有类型提示
changeDirection('up')
枚举类型
枚举:类似于字面量类型+联合类型组合的功能,表示一组明确的可选值
-
枚举既可以当做类型使用,也可以当做数据值使用
-
枚举既可以通过键取到值,也可以通过值取到键
// 定义枚举
enum Direction {
Up = 'Up',
Down = 'Down',
Left = 'Left',
Right = 'Right'
}
// 枚举可以当做类型使用
function changeDirection(direction: Direction) {
console.log(direction)
}
// 枚举也可以当做数据值使用
changeDirection(Direction.Up)
// 枚举既可以通过键取到值,也可以通过值取到键
enum ExamineStatus {
/* 待审核 */
WaitExamine = 1,
/* 审核成功 */
ExamineSuccess = 2,
/* 审核失败 */
ExamineFail = 3
}
console.log(ExamineStatus.ExamineFail)
console.log(ExamineStatus[1])
注意:
-
使用
enum
关键字定义枚举 -
约定枚举名称以大写字母开头
-
枚举中的多个值之间通过
逗号
分隔
any 类型
any 类型:逃避 TS 的类型检查。
-
当值的类型为 any 时,可以对该值进行任意操作,编辑器也不会报错,并且不会有代码提示。这样就会使代码出现问题的概率增大。
let temp: any = 11
temp = 'str' // 没有报错
temp.toFixed(2) // 没有提示。但浏览器执行代码时会报错
-
原则: 不推荐使用 any! 这会让 TypeScript 变为 “AnyScript” (失去 TS 类型保护的优势)
-
尽可能的避免使用 any 类型,但是有时候,在开发过程中,不确定类型时,可以先用 any 占位 =》确认类型后 =》再去写成具体类型
类型断言
类型断言:有时候你会比 TS 更加明确一个值的类型,此时,可以使用类型断言来指定更具体的类型。
需求:假设在页面上有一个 a 标签,<a id="link" href="xxx"></a>
,我们想要获取 a 标签 DOM 元素的 href 属性。
// 这种方式获取的元素,ts 不知道它是一个 a 标签。所以获取元素的 href 属性时,会报错。
const aLink = document.querySelector('#link')
console.log(aLink.href) // 报错
// ts 不知道,但是我们知道。所以要给它加上类型断言,告诉 ts 它就是一个 a 标签的元素类型
const aLink = document.querySelector('#link') as HTMLAnchorElement
console.log(aLink.href)
// 想要知道一个 html 元素的具体类型,可以创建该元素,然后使用鼠标悬停去摸一摸
const a = document.createElement('a')
TypeScript 泛型
泛型:可以将类型当做参数传递,从而实现复用。常用于:函数、接口、类型别名中。
泛型在函数上的应用
泛型函数:函数可以配合泛型来使用,以增加其灵活性和复用性。
需求:给 sayHi
函数传入打招呼的名字,并将该名字返回。(也就是说,参数和返回值类型相同)
// JS 通过函数传参,达到数据的复用
const sayHi1 = () => {
console.log('hello zs');
return 'zs'
}
const sayHi2 = () => {
console.log('hello ls');
return 'ls'
}
const sayHi = (name: string): string => {
console.log('hello' + name);
return name
}
sayHi('zs')
sayHi('ls')
// TS 通过类型传参,达到类型复用
// 不使用泛型
const sayHi1 = (name: string): string => {
console.log('hello' + name);
return name
}
sayHi1('zhangsan')
const sayHi2 = (name: number): number => {
console.log('hello' + name);
return name
}
sayHi2(9527)
// 使用泛型
const sayHi = <T>(name: T): T => {
console.log('hello' + name);
return name
}
sayHi<string>('zhangsan')
sayHi<number>(9527)
泛型在接口上的应用
泛型接口:接口也可以配合泛型来使用,以增加其灵活性和复用性。
// 不使用泛型
interface MyObj1 {
name: string,
sayHi(): string
}
const obj1: MyObj1 = {
name: 'zs',
sayHi() {
console.log('Hi,', this.name)
return this.name
}
}
interface MyObj2 {
name: number,
sayHi(): number
}
const obj2: MyObj2 = {
name: 9527,
sayHi() {
console.log('Hi,', this.name)
return this.name
}
}
// 使用泛型
interface IMyObj<T> {
name: T,
sayHi(): T
}
const obj1: IMyObj<string> = {
name: 'zs',
sayHi() {
console.log('Hi,', this.name)
return this.name
}
}
const obj2: IMyObj<number> = {
name: 9527,
sayHi() {
console.log('Hi,', this.name)
return this.name
}
}
内置的泛型接口:
const arr: Array<string> = ['a', 'b', 'c']
arr.push('d', 'e')
技巧:可以通过 ctrl + 鼠标左键(Mac:command + 鼠标左键)来查看具体的类型信息
泛型在类型别名上的应用
泛型别名:类型别名也可以配合泛型来使用,以增加其灵活性和复用性。
需求:对后端返回的数据进行类型定义。
// 后端返回的数据
// const res = await getUserInfo()
// 用户信息
let res1 = {
msg: '操作成功',
code: 10000,
data: {
name: 'zhangsan',
age: 18
}
}
// 商品信息
let res2 = {
msg: '操作成功',
code: 10000,
data: {
id: 10001,
goodsName: '苹果'
}
}
// 定义后端返回的数据的类型
// 不使用泛型
type UserData = {
msg: string;
code: number;
data: {
name: string;
age: number;
}
}
let res1: UserData = {
msg: '操作成功',
code: 10000,
data: {
name: 'zhangsan',
age: 18
}
}
type GoodsData = {
msg: string;
code: number;
data: {
id: number;
goodsName: string;
}
}
let res2: GoodsData = {
msg: '操作成功',
code: 10000,
data: {
id: 10001,
goodsName: '苹果'
}
}
// 使用泛型
type Data<T> = {
msg: string;
code: number;
data: T
}
type UserData = {
name: string;
age: number;
}
type GoodsData = {
id: number;
goodsName: string;
}
let res1: Data<UserData> = {
msg: '操作成功',
code: 10000,
data: {
name: 'zhangsan',
age: 18
}
}
let res2: Data<GoodsData> = {
msg: '操作成功',
code: 10000,
data: {
id: 10001,
goodsName: '苹果'
}
}