思考一个问题,JavaScript是一门非常优秀的编程语言,但是直到今天,JavaScript在类型检测上依然是毫无进展,所以我们需要学习TypeScript,这不仅仅可以为我们的代码增加类型约束,而且可以培养我们前端程序员具备类型思维
目录
一、认识TypeScript
TypeScript: JavaScript With Syntax For Types.
GitHub说法:TypeScript is a superset of JavaScript that compiles to clean
TypeScript官网:TypeScript is a typed superset of JavaScript that compiles to plain JavaScript.
翻译一下:TypeScript是拥有类型的JavaScript超集,它可以编译成普通、干净、完整的JavaScript代码。
- JavaScript所拥有的特性,TypeScript全部都支持
- 在语言层面上,不仅仅增加了类型约束,而且包括一些语法的扩展
- TypeScript在实现新特性的同时,总是保持和ES标准的同步甚至是领先
- TypeScript最终会被编译成JavaScript代码,不需要担心兼容性问题
- TypeScript不仅让JavaScript更加安全,而且给它带来了诸多好用的好用特性
安装TypeScript
# 安装命令
npm install typescript -g
# 查看版本
tsc --version
二、配置TypeScript的环境
1. 使用ts-node
01 - 安装ts-node及其依赖包
npm install ts-node tslib @types/node -g
02 - 代码栗子,创建 .ts 文件
// 规定message的类型为string
let message: string = 'hello'
// 报错!
// message = 123
// 规定参数类型为string
function abc(name: string){}
console.log(message);
// 因为ts默认作用域会在一个,这样设置导出,会让文件形成单独作用域
export {}
03 - 使用 ts-node
// ts-node可以直接运行TypeScript代码
ts-node 文件名
2. 使用webpack进行配置
具体可看之前的webpack文章,webpack 之 零基础使用常用的Loader ,这里我快速过一遍哈
01 - 项目初始化
npm init -y
02 - 安装各种东东
npm install webpack webpack-cli webpack-dev-server html-webpack-plugin ts-loader typescript -D
03 - 新增一个index.html模版
04 - package.json配置
05 - webpack.config.js配置
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
mode: 'development',
entry: './src/main.ts',
output: {
path: path.resolve(__dirname, './dist'),
filename: 'boundle.js'
},
devServer: {},
resolve: {
extensions: ['.js', '.ts', '.json']
},
module: {
rules: [
{
test: /\.ts$/,
loader: 'ts-loader'
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: './index.html'
})
]
};
06 - 生成tsconfig.json
// 先不用理这个文件,后续讲解
tsc --init
07 - 创建src文件夹,里面再创建main.ts
const message: string = '123'
console.log(message);
08 - npm run serve运行即可
三、变量的声明
01. 声明变量的关键字
声明了类型后TypeScript就会进行类型检测,声明的类型可以称之为类型注解
数据类型的大小写是有区别的 ,用小写即可
- string ( 小写 ) 是TypeScript中定义的字符串类型
- String ( 大写 ) 是ECMAScript中定义的一个类
02. 类型推导/推断
如果不写数据类型,会讲赋值的值的类型,作为标识符的类型
四、 TypeScript的数据类型
01. number 类型
let demo: number = 22; // 十进制
let demo: number = 0b110; // 二进制
let demo: number = 0o555; // 八进制
let demo: number = 0xf23; // 十六进制
02. boolean 类型
let bool: boolean = true
let bool: boolean = 30 > 20
03. tring 类型
const name: string = 'star'
const info: string = `my name is ${name}`
04. Array 类型
// 需要制定数组类型,同时制定数组内部值的类型
// 写法一 : 不推荐
const name: Array<string> = []
// 写法二 : 推荐
const name: string[] = []
05. 对象 类型
// 使用自动推导即可
const info = {
name: 'star',
age: 18
};
06. null 类型
const n: null = null
07. undefined 类型
const n: undefined = undefined
08. symbol 类型
// Symbol 生成独一无二的key
const info = {
[Symbol('name')]: 'star',
[Symbol('name')]: 'coder'
};
09. any 类型
// 任意类型都可赋值,也可赋值给任何类型
let message: any = 'star';
message = 123;
message = true;
10. unknown 类型
function foo() {
return 'string';
}
function bar() {
return 123;
}
let flag: boolean = true;
// result 不知是什么类型时可用
let result: unknown;
if (flag) {
result = foo();
} else {
result = bar();
}
和any类型的区别
- unknown类型只能赋值给unknown类型和any类型
- any类型可以赋值给任何类型
let result: unknown;
// 报错
let num: number = result
// 可以赋值
let unres: unknown = result
let anyres: any = result
11. void 类型
// 当函数没有返回值的时候,该函数就是void类型,不写也阔以,会自动推导
const sum = (num1: number, num2: number): void => {
console.log(num1, num2);
};
12. never 类型
// 当永远没有返回值的时候,用never
function foo(): never {
while (true) {}
}
function bar(): never{
throw new Error()
}
13. tuple 元组类型
// tuple 多种元素的组合
const info: [string, number, number, string] = ['star', 1, 2, 'coder'];
14. 函数的参数及返回值 类型
// 可指定函数的参数类型和个数和返回值的类型 name: string => 指参数类型为string string => 指函数的返回值类型为string,可不写,会推导
function getInfo(name: string): string {
return name;
}
// 匿名函数不需要写类型,TypeScript会根据forEach函数的类型以及数组的类型 推断出 item的类型
// 因为函数执行的上下文可以帮助确定参数和返回值的类型
const names = ['a', 'b', 'c'];
names.forEach((item) => {});
15. {} 对象类型
// info是一个对象类型,对象中有两个属性
function find(info: { name: string; age: number }) {}
16. ? 可选类型
// money是可选类型,可传可不传
function find(info: { name: string; age: number; money?: number }) {}
find({ name: 'coder', age: 123 });
find({ name: 'coder', age: 123, money: 1000 });
17. | 联合类型
// 联合类型 可以为其中的一种
function find(id: string | number) {
// 使用联合类型的值的时候,需要特别小心
switch (typeof id) {
case 'string':
break;
case 'number':
break;
}
}
find(123);
find('456');
可选类型和联合类型的关系
一个参数是一个可选类型的时候,它其实类似于这个参数是 类型|undefined的联合类型
function foo(message?: string) {}
// 这里可以不传
foo();
function foo(message: string | undefined) {}
// 但是这里还是要传一个值
foo(undefined);
18. type 类型别名
// type 用于定义类型别名
type IdType = string | number | boolean;
// 太长了
function idSet(id: string | number | boolean) {}
// 取别名可以优化
function idSet(id: IdType) {}
19. as 类型断言
// 默认是 HTMLElement 类型,范围太广了,有时会出错
// const oDom: HTMLElement = document.getElementById('star');
// <img id="star" />
// 用 as 指定是什么元素类型
const oDom: HTMLImageElement = document.getElementById('star') as HTMLImageElement;
oDom.src = 'url地址';
// 不推荐乱使用
const message = 'hello'
// 可以跳过类型检测,无敌,不推荐使用
const num: number = (message as any) as number
20. ! 非空类型断言
// 这样是没问题的
function printStrLength(message: string) {
console.log(message.length);
}
printStrLength('aaa');
printStrLength('11');
// 但是如果参数变成了可选类型呢,编译就会报错
function printStrLengthCan(message?: string) {
console.log(message.length);
}
// 解决方式一
function printStrLengthOne(message?: string) {
// 做个if判断即可
if (message) {
console.log(message.length);
}
}
// 解决方式二
function printStrLengthTwo(message?: string) {
// 加个非空断言 , 保证message一定有值
console.log(message!.length);
}
21. ?.可选链
可选链事实上并不是TypeScript独有的特性,它是ES11(ES2020)中增加的特性
- 可选链使用可选链操作符 ?.
- 它的作用是当对象的属性不存在时,会短路,直接返回undefined,如果存在,那么才会继续执行
// 定义一个类型
type Person = {
name: string;
// 可能有,可能没有
friend?: {
name: string;
// 可能有,可能没有
age?: number;
};
};
const info: Person = {
name: 'star'
};
const info2: Person = {
name: 'star',
friend: {
name: 'coder'
}
};
// 如果有friend,继续往后取,如果没有,返回undefined,相当于短路
console.log(info.friend);
console.log(info.friend?.name);
console.log(info.friend?.age);
// 类似于,可以节省很多代码
if (info.friend) {
if (info.friend.name) {
console.log(info.friend.name);
}
if (info.friend.age) {
console.log(info.friend.age);
}
}
export {};
22. !! 取boolean类型
const message: string = 'hello'
const flag: boolean = Boolean(message)
// !! 可以用作取反
const flag1: boolean = !!message
23. ??
// ?? 有值的时候取前面的值,没值的时候取后面的值
// 和三目运算符很像,不过更简洁一点
const message: string | null = null;
const res: string = message ?? 'hello';
console.log(res); // hello
const message1: string | null = 'coder';
const res1: string = message ?? 'hello';
console.log(res1); // coder
24. 字面量类型
字面量类型的类型和值要保持一致
const message = 'hello'; // 这个message的类型就是hello
let mess = 'hello' //这个mess的类型才是string
let me : 123 = 123
me = 456 // 报错
字面量类型的意义 : 必须结合联合类型
let align: 'left' | 'right' | 'center' = 'left'
// 再次修改值的时候,只能允许修改定义了类型的值
align = 'right'
25. 字面量推理
栗子
const info = {
url: 'www.baidu.com',
method: 'GET'
};
function request(url: string, method: 'GET' | 'POST') {
console.log(url, method);
}
// 这里info.method会报错,因为默认推导method是字符串类型,所以不能这么传
request(info.url,info.method)
解决方式一 : 推荐
// 定义一个类型
type requestType = {
url: string;
method: 'GET' | 'POST';
};
// 定义对象的时候就使用这个类型
const info: requestType = {
url: 'www.baidu.com',
method: 'GET'
};
function request(url: string, method: 'GET' | 'POST') {
console.log(url, method);
}
request(info.url, info.method);
解决方式二 :
const info = {
url: 'www.baidu.com',
method: 'GET'
};
function request(url: string, method: 'GET' | 'POST') {
console.log(url, method);
}
// 使用类型断言
request(info.url, info.method as 'GET');
解决方式三 :
function request(url: string, method: 'GET' | 'POST') {
console.log(url, method);
}
// 这里使用类型断言成const,其内部的属性值都变成了readeronly
const info = {
url: 'www.baidu.com',
method: 'GET'
} as const;
request(info.url, info.method);
export {};