
TypeScript魔法指南:解锁类型安全的新境界
TypeScript(简称 TS)是微软公司开发的一种基于JavaScript 语言的编程语言。它是JavaScript 的超集,其目的是增强 JavaScript的功能,本质上向这个语言添加了可选的静态类型和基于类的面向对象编程。
前言
📫 大家好,我是南木元元,热爱技术和分享,欢迎大家交流,一起学习进步!
🍅 个人主页:南木元元
目录
什么是TypeScript
TypeScript(简称 TS)是微软公司开发的一种基于JavaScript 语言的编程语言。它是JavaScript 的超集,其目的是增强 JavaScript的功能,本质上向这个语言添加了可选的静态类型和基于类的面向对象编程。
TypeScript的优缺点
优点:
- 增强代码的可维护性,尤其在大型项目的时候效果显著
- 提供了一套静态类型检查机制 ,编译阶段就能检查类型发现错误
- 周边生态繁荣,vue3已全面支持 typescript
缺点:
- 增加一些学习成本
- 增加前期开发的成本,毕竟需要写更多的代码
动态类型与静态类型
TypeScript属于静态类型语言。那么什么静态类型,什么是动态类型呢?
动态类型语言:运行时才做数据检查的语言,如JavaScript、Ruby、Python等。
静态类型语言:编译阶段进行数据类型检查,如C、C++、C#、Java等。
安装TypeScript
TypeScript官网地址:https://www.typescriptlang.org/zh/
使用nvm来管理Node版本:https://github.com/nvm-sh/nvm
全局安装TypeScript:
npm install -g typescript
使用tsc全局命令:
// 查看tsc版本
tsc -v
// 编译ts文件
tsc fileName.ts
新建一个test.ts文件,随便写点什么:
const hello = (name: string) => {
return `hello ${name}`
}
hello('南木元元')
控制台执行tsc test.ts命令,编译文件,此时目录下生成了一个同名的 test.js 文件,代码如下:
var hello = function (name) {
return "hello ".concat(name);
};
hello('南木元元');
通过tsc命令,发现我们的ts代码被转换成了熟悉的js代码。
TypeScript基础类型
Boolean类型
let flag: boolean = false;
Number类型
let age: number = 18;
String类型
let name: string = '元元'
Null和Undefined类型
默认情况下 null 和 undefined 是所有类型的子类型, 也就是说可以把 null 和 undefined 赋值给其他类型。
let u: undefined = undefined;
let n: null = null;
// 可以将undefined赋值给number类型
let num: number = undefined;
Any类型
在 TypeScript 中,任何值都可以赋值给any类型。
let notSure: any = 369;
notSure = 'yuanyuan';
notSure = true;
Array数组类型
//定义一个数字类型的数组
let arr: number[] = [1,2,3];
arr.push(4);
Tuple元组类型
数组类型中的值只能是同种类型,如果想要在一个数组中使用不同类型的值,就可以使用元组。
//定义一个长度为2的元组
let user: [string, number] = ['yuanyuan', 18];
元组的长度是固定的,并且类型必须对应。
Enum枚举类型
使用枚举我们可以定义一些带名字的常量,可以清晰地表达意图,如周一到周日,上下左右等。
- 数字枚举
enum Direction {
Up,
Down,
Left,
Right,
}
console.log(Direction.Up) //0
Up
初始值默认为 0, 其余的成员会会按顺序自动增长。
- 字符串枚举
enum Direction {
Up = 'UP',
Down = 'DOWN',
Left = 'LEFT',
Right = 'RIGHT',
}
console.log(Direction.Up) //UP
//用法示例:比如后端返回一个值'UP',就可以去做相应的事
let value = 'UP'
if(value === Direction.Up) {
//do something
}
- 常量枚举
使用 const 关键字修饰的枚举,常量枚举会在编译阶段被删除,提升性能。
普通枚举编译后的结果:
enum Direction {
Up = 'UP',
Down = 'DOWN',
Left = 'LEFT',
Right = 'RIGHT',
}
let value: string = 'UP'
if(value === Direction.Up) {
//do something
}
// 编译后的结果
var Direction;
(function (Direction) {
Direction["Up"] = "UP";
Direction["Down"] = "DOWN";
Direction["Left"] = "LEFT";
Direction["Right"] = "RIGHT";
})(Direction || (Direction = {}));
var value = 'UP';
if (value === Direction.Up) {
//do something
}
常量枚举编译后的结果:
//常量枚举
const enum Direction {
Up = 'UP',
Down = 'DOWN',
Left = 'LEFT',
Right = 'RIGHT',
}
let value: string = 'UP'
if(value === Direction.Up) {
//do something
}
// 编译后的结果
var value = 'UP';
if (value === "UP" /* Direction.Up */) {
//do something
}
Interface接口
interface的作用是对对象的形状进行描述,定义的变量比接口少或多一些属性都是不允许的。
//使用interface声明接口Person
interface Person {
name: string;
age: number;
};
//约束了 变量yuanyuan 的形状必须和接口 Person 保持一致
let yuanyuan: Person = {
name: 'yuanyuan',
age: 18
};
设置可选 | 只读属性:
- 可选属性:接口里的属性不全都是必需的,只在某些条件下存在。
- 只读属性:只读属性只能在对象刚刚创建的时候修改其值。
interface Person {
readonly id: number; //只读属性, 属性名前用readonly来指定
age?: number; //可选属性, 在可选属性名字定义的后面加一个?
};
let yuanyuan: Person = {
id: 1
};
yuanyuan.id = 66; //会报错,不能修改只读属性
函数
- 函数声明
function add(x: number, y: number): number {
return x + y;
}
- 函数表达式
const add = (x: number, y: number): number => {
return x + y;
}
- 接口定义函数
interface Add {
(x: number, y: number): number
}
let add2: Add = add;
类型推论
TypeScript里,在有些没有明确指出类型的地方,类型推论会帮助提供类型。
let x = 3;
x = true; // 报错
变量x的类型被推断为数字。
联合类型
联合类型用|分隔,表示取值可以为多种类型中的一种。
let numberOrString: number | string
numberOrString = "yuayuan"
numberOrString = 18
类型断言
某些情况下,我们可能比typescript更加清楚的知道某个变量的类型。
这时可以通过类型断言这种方式手动指定一个值的类型,即告诉编译器“我很清楚自己在干什么”。
function getLength(input: string | number): number {
const str = input as string //类型断言
if(str.length) {
return str.length;
} else {
const number = input as number
return number.toString().length
}
}
上述代码要返回联合类型input的长度,由于number是没有length方法的,所以可以使用类型断言来做处理。
类型守卫
类型守卫可以在运行时用于检查和过滤变量类型,通常用于条件语句中,来检查变量的类型并相应地执行不同的逻辑。常用的类型守卫有typeof和instanceof。
使用类型守卫来改写上述代码:
function getLength2(input: string | number): number {
if(typeof input === 'string') {
return input.length;
} else {
return input.toString().length;
}
}
泛型
现在要实现一个函数,函数的参数可以是任何值,返回值就是将参数原样返回。
function echo(arg: number): number {
return arg
}
上面的函数只能传入number类型的参数,返回类型也为number,但如果传入的是string、boolean就不能满足了。
是的,可以直接使用any,但使用 any 的话,怎么写都是 ok 的, 这就丧失了类型检查的效果。
function echo(arg: any): any {
return arg
}
const res: string = echo(123)
上述代码中,传入并返回number类型的值,但是使用string类型的参数来接受,由于使用的是any,编译器不会报错,这就会导致问题。
这时就可以使用泛型。
基本使用
泛型是指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型的一种特性。
function echo<T>(arg: T): T {
return arg
}
定义函数时使用尖括号<>,里面添加一个类型变量T,T用于表示类型而不是值,只有在调用的时候才会确定类型,这样就能使得参数类型与返回值类型是相同的了。
使用泛型后,上面的BUG就会被修复。
了解了泛型后,现在如果要交换元组中的两个任意类型值的位置并返回,可以这么写:
function swap<T, U>(tuple: [T, U]): [U, T] {
return [tuple[1], tuple[0]]
}
const res2 = swap(['string', 123]) //已经交换了位置
可以看到,两个值就已经交换了位置。
泛型约束
下面代码会报错,因为编译器并不能证明每种类型都有length属性。
function getLength<T>(arg: T): T {
console.log(arg.length) //报错,类型T上不存在属性length
return arg
}
这时,可以定义一个接口来描述约束条件。 创建一个包含 .length属性的接口,使用这个接口和extends关键字来实现约束。
interface Lengthwise {
length: number
}
function getLength<T extends Lengthwise>(arg: T): T {
console.log(arg.length)
return arg
}
使用:
const str = getLength('str')
const obj = getLength({length: 10})
const arr = getLength([1, 2, 3])
这里可以看出,不管你是 str,obj还是arr ,只要具有 length 属性,都是可以的。
泛型类
class Test<T> {
value: T;
add: (x: T, y: T) => T;
}
let myTest = new Test<number>();
myTest.value = 0;
myTest.add = function (x, y) {
return x + y;
};
泛型接口
在定义接口的时候指定泛型。
interface KeyValue<T, U> {
key: T;
value: U;
}
const person1: KeyValue<string, number> = {key: 'yuan', value: 18}
const person2: KeyValue<number, string> = {key: 18, value: 'yuan'}
类型别名
类型别名用来给一个类型起个新名字。
type Message = string | string[];
let greet = (message: Message) => {
// ...
};
交叉类型
交叉类型就是跟联合类型相反,用&操作符表示,交叉类型就是两个类型必须存在,常用于将多个接口类型合并成一个类型。
interface personA {
name: string;
age: number;
}
interface personB {
name: string;
gender: string;
}
let person: personA & personB = {name: "yuan", age: 18, gender: "男"};
结语
🔥如果此文对你有帮助的话,欢迎💗关注、👍点赞、⭐收藏、✍️评论,支持一下博主~
更多推荐
所有评论(0)