TypeScript入门详解
TypeScript初识
TS是带类型语法的JS
TypeScript
是一种带有 类型语法
的 JavaScript 语言,在任何使用 JavaScript 的开发场景中都可以使用。
JavaScript 代码
// 没有明确的类型
let age = 18
TypeScript 代码
// 有明确的类型,可以指定age是number类型(数值类型)
// let 变量名 : 数据类型 = 值
let age: number = 18
注意:TS 需要编译才能在浏览器运行。
总结:TS 是 JS 的超集,支持了JS 语法和扩展了类型语法。
TypeScript 作用
TS作用是在编译时进行类型检查提示错误
- JS是动态类型的编程语言,动态类型最大的特点就是它只能在
代码执行
期间做类型的相关检查,所以往往你发现问题的时候,已经晚了。 - TS 是静态类型的编程语言,代码会先进行编译然后去执行,在
代码编译
期间做类型的相关检查,如果有问题编译是不通过的,也就暴露出了问题。 - 配合 VSCode 等开发工具,TS 可以提前到在
编写代码
的时候就能发现问题,更准确更快的处理错误。
TS 优势
- 更早发现错误,提高开发效率
- 随时随地提示,增强开发体验
- 强大类型系统,代码可维护性更好,重构代码更容易
- 类型推断机制,减少不必要类型注解,让编码更简单
☆ Vue3源码TS重写,React和TS完美配合,Angular默认支持TS,大中型前端项目首选。
TypeScript 核心
类型注解
示例代码 :
// 约定变量 age 的类型为 number 类型
let age : number = 18;
age = 19;
: number
就是类型注解,它为变量提供类型约束。- 约定了什么类型,就只能给该变量赋值什么类型的值,否则会报错。
- 而且:约定类型之后,代码的提示也会非常清晰。
错误演示 :
let age: number = 18;
// 报错:不能将类型“string”分配给类型“number”
age = '19';
总结 :
什么是类型注解?
变量后面约定类型的语法
,就是类型注解类型注解作用?
类型约束
,明确提示
TS常用类型
-
JS 已有类型
- 简单类型,
number
string
boolean
null
undefined
- 复杂类型,对象 数组 函数
- 简单类型,
-
TS 新增类型
- 联合类型、自定义类型(类型别名)、接口、元组、字面量类型、枚举、void、any、泛型 等
原始类型
语法 : :数据类型
- js基本数据类型 :
string / number / boolean / null / undefined
- null 和 undefined使用较少 , 一般作为初始值
/**
* 原始类型
*/
{
// 1.数字类型
let number : number = 1
// 2.字符串类型
let string : string = '2'
// 3.布尔类型
let boolean : boolean = true
// 4.null
let nullValue : null = null
// 5.undefined
let undefinedValue = undefined
}
数组类型
数组类型注解分为两种
- 写法一 :
类型[]
{
//语法 :`类型[]`
// 数字数组
let numArr : number[] = [1,2,3]
// 字符串数组
let strArr : string[] = ['1','2','3']
}
- 写法二 :
Array<类型>
//语法 :`Array<类型>`
// 布尔类型数组
let booleanArr : Array<boolean> = [true , false]
}
推荐使用: 类型[]
写法
联合类型
类型与类型之间使用 |
连接,代表类型可以是它们当中的其中一种,这种类型叫:联合类型
( 联合类型可以将多个类型合并为一个类型 )
☆ 示例 :数组中有 number
和 string
类型,这个数组的类型如何书写?
let arr: (number | string)[] = [1, 'a', 3, 'b'];
☆ 案例 :给一个定时器 ID 加类型
- 初始化timer ,timer类型为null
- 给timer赋值定时器 , 此时timer类型为number类型
// timer 的类型注解是数字类型或null类型
let timer: number | null = null;
timer = setInterval(() => {}, 1000);
类型别名
基本语法 : type 类型别名 = 具体类型
基本语法
- 定义类型别名,遵循大驼峰命名规范,类似于变量
- 使用类型别名,与类型注解的写法一样即可
示例代码 :
// let arr: ( number | string )[] = [ 1, 'a', 4]
// 类型别名: type 类型别名 = 具体类型
type CustomArr = (number | string)[];
let arr: CustomArr = [1, 'a', 4];
总结 : 当同一类型(写法复杂)被多次使用时,可以通过类型别名,
简化
该类型的使用 , 提高代码的复用性 ,方便后期维护
函数类型
给函数指定类型,其实是给 参数
和 返回值
指定类型
两种写法:
- 在函数基础上
分别指定
参数和返回值类型 - 使用类型别名
同时指定
参数和返回值类型
示例代码 :分别指定
// 函数声明
function add(num1: number, num2: number): number { return num1 + num2; }
// 箭头函数
const add = (num1: number, num2: number): number => { return num1 + num2; };
示例代码 :同时指定
type AddFn = (num1: number, num2: number) => number;
const add: AddFn = (num1, num2) => {
return num1 + num2;
};
☆注意:
通过类似箭头函数形式的语法来为函数添加类型,只适用于
函数表达式
void 类型
void
是函数返回值类型
- 如果函数没有返回值,定义函数类型时返回值类型为
void
const say = (): void => {
console.log('hi');
};
- 如果函数没有返回值,且没有定义函数返回值类型的时候,默认是
void
const say = () => {
console.log('hi');
};
可选参数
如果函数的参数,可以传也可以不传,这种情况就可以使用 可选参数
☆ 语法 : 参数后加 ?
即可
const fn = (n?: number) => { // .. };
fn(); // 可以不传参
fn(10);
注意: 必选参数不能位于可选参数后
对象类型
TS 的对象类型,其实就是描述对象中的 属性
方法
的类型,因为对象是由属性和方法组成的。
空对象 :
let person: {} = {};
有属性的对象 :
let person: { name: string } = {
name: '同学'
};
有属性和方法的对象
let person: {
name: string;
sayHi(): void;
} = {
name: 'jack',
sayHi() {},
};
小结 :
- 使用声明描述对象结构?
{}
- 属性怎么写类型?
属性名: 类型
- 方法怎么写类型?
方法名(): 返回值类型
对象类型-扩展用法:
- 函数使用箭头函数类型
let person: { name: string sayHi: () => void } = { name: 'jack', sayHi() {}, };
- 对象属性可选
// 例如:axios({url,method}) 如果是 get 请求 method 可以省略 const axios = (config: { url: string; method?: string }) => {};
- 使用类型别名
// {} 会降低代码可阅读性,建议对象使用类型别名 // const axios = (config: { url: string; method?: string }) => {}; type Config = { url: string; method?: string; }; const axios = (config: Config) => {};
小结:
- 对象的方法使用箭头函数类型写法 :
{sayHi:()=>void}
- 对象的可选参数设置 :
{name?: string}
- 对象类型会使用
{}
如何提供可阅读性?类型别名
接口 interface
接口声明是命名对象类型的另一种方式
// 通过interface定义对象类型
interface Person {
name: string;
age: number;
sayHi: () => void;
}
// 使用类型
let person: Person = {
name: 'jack',
age: 19,
sayHi() {},
};
小结:
interface
后面是接口名称,和类型别名的意思一样。- 指定
接口名称
作为变量的类型使用。 - 接口的每一行只能有
一个
属性或方法,每一行不需要加分号。
interface 继承
语法 : 接口A extends 接口B
使用场景 :有两个接口,有相同的属性或者函数,如何提高代码复用?
// 两个接口有相同的x,y属性
interface Point2D {
x: number;
y: number;
}
interface Point3D {
x: number;
y: number;
z: number;
}
可以将相同的属性或展示可以抽离出来,然后使用 extends
实现继承复用:
interface Point2D {
x: number;
y: number;
}
// 继承 Point2D
interface Point3D extends Point2D {
z: number;
}
// 继承后 Point3D 的结构:{ x: number; y: number; z: number }
小结:
- 接口继承的语法:
interface 接口A extends 接口B {}
- 继承后
接口A
拥有接口B
的所有属性和函数的类型声明
type 交叉类型
语法 : type1 &
type2
使用场景 : 实现 Point2D
与 {z: number}
类型合并得到 Ponit3D
类型
// 使用 type 来定义 Point2D 和 Point3D
type Point2D = {
x: number;
y: number;
};
// 使用 交叉类型 来实现接口继承的功能:
// 使用 交叉类型 后,Point3D === { x: number; y: number; z: number }
type Point3D = Point2D & {
z: number;
};
let obj: Point3D = {
x: 1,
y: 2,
z: 3,
};
小结:
- 使用
&
可以合并连接的对象类型,也叫:交叉类型
interface & type
- 类型别名和接口非常相似,在许多情况下,可以在它们之间
自由选择
。 - 接口的几乎所有特性都以类型的形式可用,关键的区别在于不能重新打开类型以添加新属性,而接口总是
可扩展
的。
interface和type的相同点 :
- 都可以声明对象类型
- 都可以复用
interface和type的不同点 :
- type可以声明其他类型 , interface不可以
- type复用语法 : &交叉类型 ; interface复用语法 :extends
- type不可以重复声明 , 会报错 ; interface可以重复声明 , 属性和方法会合并
类型推断
在 TS 中存在类型推断机制,在没有指定类型的情况下,TS 也会给变量提供类型。
- 声明变量并初始化时
// 变量 age 的类型被自动推断为:
number let age = 18;
- 决定函数返回值时
// 函数返回值的类型被自动推断为:number
const add = (num1: number, num2: number) => {
return num1 + num2;
};
建议:
- 将来在开发项目的时候,能省略类型注解的地方就省略,
充分利用TS推断
的能力,提高开发效率。 - 在你还没有熟悉 ts 类型的时候建议都加上类型,比如今天第一次写 ts 最好都写上
- 如果你不知道类型怎么写,可以把鼠标放至变量上,可以通过
Vscode
提示看到类型
字面量类型
使用 js字面量
作为变量类型,这种类型就是字面量类型
// : 'jack' 是字面量类型
let name: 'jack' = 'jack';
// : 18 是字面量类型
let age: 18 = 18;
// 报错:不能将类型“19”分配给类型“18”
age = 19;
字面量类型应用 : 性别只能是男和女 ,不会出现其他值
type Gender = '男' | '女' let gender: Gender = '男' gender = '女'
小结:
- 字面量类型配合
联合类型
来使用,表示:一组明确的可选的值
类型断言
有时候自己会比 TS 更加明确一个值的类型,此时,可以使用类型断言来指定更具体的类型 , 例如 : a标签
// aLink 的类型 HTMLElement,该类型只包含所有标签公共的属性或方法
// 这个类型太宽泛,没包含 a 标签特有的属性或方法,如 href
const aLink = document.getElement(#link)
- 我们明确知道获取的是一个
a
标签,可以通过类型断言
给它指定一个更具体的类型
const aLink = document.getElementById('link') as HTMLAnchorElement
小结:
- 使用
as
关键字实现类型断言 - 关键字
as
后面的类型是一个更加具体的类型(HTMLAnchorElement 是 HTMLElement 的子类型) - 通过类型断言,aLink 的类型变得更加具体,这样就可以访问 a 标签特有的属性或方法了
三种方法可以获取具体类型进行类型断言:
- console.dir()
打印标签
- document.createElement('a')
创建元素
- document.queryselector('img')
获取元素
转载自:https://juejin.cn/post/7259686845969252410