这是我参与「第五届青训营 」伴学笔记创作活动的第 4 天
学习TypeScript的基础语法,了解其高级应用
TS发展与基础语法
为什么是TS?
👉TS发展历史
- 2012-10:微软发布第一个版本
- 2014-10:Angular 发布基于TS的2.0版本
- 2015-04:微软发布VScode(最支持TS的开发软件)
- 2016-05:@type/react发布,TS可以开发React
- 2020-09:Vue3版本支持TS
- 2021-11:TS v4.5版本发布
👉JS VS TS
- (JS)动态类型 VS (TS)静态类型
- 静态类型:可读性强、可维护性强、合作项目中能有更好的稳定性和开发效率
- TS是JS的超集:包含与兼容JS的所有特性,支持共存;支持渐进式引入与升级
静态类型语言中,变量的类型必须先声明,即在创建的那一刻就已经确定好变量的类型,而后的使用中,你只能将这一指定类型的数据赋值给变量。如,一旦声明一个变量是int类型,之后就只能将int类型的数据赋值给它,否则就会引发错误。
动态类型则没有这样的限制,你将什么类型的数据赋值给变量,这个变量就是什么类型。
- 都是弱类型语言
- 强弱之分,体现在对类型的检查严格程度上,弱类型语言对于变量类型的检查比较宽松,容忍隐式类型转换。隐式类型转换,一般有两种形式:
- 相关类型之间隐式转换:如 int + float = float, int 先转换为 flaot 再相加
- 不相关类型之隐式间转换:如 int + string = string, int 先转换为 string 再合并
- 在弱类型语言中,变量可以隐式强制转换为不相关类型,而在强类型语言中则不可以。
- 强弱之分,体现在对类型的检查严格程度上,弱类型语言对于变量类型的检查比较宽松,容忍隐式类型转换。隐式类型转换,一般有两种形式:
TS的基本语法
👉基础数据类型
- any, string, numberm, boolean, null, undefined...
- 如
const q: string = 'string'
👉 type关键字(类型别名)
- 用于定义类型,不同于
interface只能定义对象类型,type声明的方式可以定义任意类型。 - 字符串/数字的字面量,允许指定固定值,
type IOddNum = 1|3|5|7|9
👉接口与对象
- 接口是一系列抽象方法的声明,可用于定义对象类型
- 命名以I开头,用于区分TS自带的对象
interface IMyInterface {
// 只读,定义后不可修改
readonly stuId: number;
name: string;
sex: 'man'| 'woman'| 'other';
age: number;
// 可选属性,定义时可以不写
hobby?: string;
// 任意属性,添加的新的其它属性的类型都必须是该类型的子类型
[key: string]: any;
}
const ddInterface: IMyInterface= {
stuId: 20230119,
name: 'dede',
sex:'woman',
age: 23,
hobby: 'code',
platform: 'ByteDancer'
}
console.log(ddInterface);
👉函数
- 需要声明类型的地方:传入和传出(返回)的参数
- 传入参数可以设置成:可选、有默认值、剩余参数等
- 可以使用接口实现
function fn(name:string, age:number = 23, hobby?:string, ...restOfArgs: string[]): string{
return 'Hi';
}
// 接口
interface IMult {
(x: number, y: number): number;
}
const mult: IMult = (x, y) => x * y;
👉数组
- 类型+[] (常用)
- 泛型generics,对类型编程(常用)
- 元祖:允许存储不同类型的元素
- 接口实现
type IArr1 = number[];
type IArr2 = Array<string | number | Record<string, number>>;
type IArr3 = [number, number, string, string]
interface IArr4 {[key: number]: any;}
const arr1: IArr1 = [1, 2, 3, 4];
const arr2: IArr2 = ['aa', 1, 2, { b: 3 }];
const arr3: IArr3 = [1, 2, '3', '4'];
const arr4: IArr4 = ['string', 100, {}, () => null]
👉其它补充类型
- 空类型,表示无赋值
- 枚举类型(E开头): 支持枚举值与枚举名的正反映射
type IEmptyFn = () => void
enum EExample {
add = '+',
mult = '*',
}
EExample['add'] === '+';
EExample['*'] === 'mult';
👉泛型
- 不预先指定具体的类型,在使用的时候再指定(对类型编程)
- 对比两个GetArr
- 不使用泛型,会产生输入number,返回string[]的情况。
- 使用了泛型能保证输入了number,返回number的数组,即输入什么类型返回什么类型,
- 泛型还可以用于接口、类、类型别名等。
type IGetArr1 = (target: any) => any[];
type IGetArr2 = <T>(target: T) => <T>[];
interface IX<T,U> {
key: T;
val: U;
}
class IM<T> { instance: T; }
type ITypeArr<T> = Array<T>
- 泛型约束:限制泛型必须限定在一定范围内(使用
extends关键字) - 泛型参数默认类型:
type IGetString<T = string> = (target:T) =>T[]
高级应用
联合/交叉类型
-
联合类型:
IA | IB, 一个值可以是几种类型- 类型保护:TS处于程序安全考虑,仅允许访问联合类型的交集部分(JS都可以访问)
- 类型守卫:定义一个函数,返回一个类型谓词
-
交叉类型:
IA & IB多种类型叠加到一起成为一种类型
// JS
const bookList = [
{
author: 'xiaoming',
type: 'history',
range: '2001-2021',
}, {
author: 'xiaohong',
type: 'story',
theme: 'love',
}]
// TS
type IBookList = Array<{
author: string;
} & ({
type: 'history',
range: '2001-2021',
} | {
type: 'story',
theme: 'love',
})>
// 联合类型 + 类型保护 = 自动类型推断
function logBookInfo(book: IBookList) {
if(book.type == 'history') { // 交集为type
console.log(book.range);
} else {
console.log(book.theme);
}
}
TS的工程应用
浏览器web👉webpack
- 配置webapack loader相关配置
- 配置tsconfig.js 文件
- 运行webpack启动/打包
Node👉tsc编译
npm install -g typescript- ts文件转换为js文件:
tsc hello.ts - 执行js文件:
node hello.js