TypeScript基础知识点
1.TypeScript介绍
TypeScript是一门基于javascript的编程语言,它是具有类型系统的javascript,是一种解决javascript缺点的编程语言。
//所有的 javascript代码 其实都是合法的 typescript 代码
var a = 10;
function fn() {}
if(true) {}
for (var i = 0; i < 10; i++) {}
// typescript 是静态类型编程语言,即编译期间进行类型检查,变量,参数,返回值等都必须有固定的类型。
let x :number = 10;
x = 20; // ✅
x = "a"; // ❎
- TypeScript不能在浏览器环境或者Node环境直接运行,它在执行前需要先被编译为javascript。
//typescript
let isLogin: boolean = false;
//javascript
let isLogin = false;
Typescript 提供的类型系统只应用在开发阶段,只有在开发阶段开发者才需要借助它编写出更加健壮的程序
1.1类型系统带来的好处
通过静态类型检查可以让开发者在编译时就发现错误而不是在代码运行时。
类型系统为编辑器带来了更加精准的代码提示,以此来提升开发人员的编程体验
app.get("/",function(req,res){
res.
send
sendData
sendfile
sendFile
sendStatus
})
在生命变量时明确告知编译器它的类型,编译器就知道该变量可以调用哪些属性和方法,当开发者调用了错误的属性或方法时,编译器会及时给出提示
var name:string = "张三";
name.toFixed(2) //属性"toFixed“在类型“string”上不存在
在声明函数时明确告知编译器参数的类型,当开发者调用该函数时如果传递的参数类型不正确,编译器会及时给出提示。
function sum(x: number, y:number) {}
sum(10,"a"); //类型string的参数时不能赋予给类型 number的参数
在生命函数时明确告知编译器返回值的类型,当开发者返回的值的类型错误时,编译器会及时给出提示
function sayHello():string {
return 100 //不能将类型"number" 分配给类型 "string"
}
在声明对象时告知编译器该对象下有哪些属性;当开发者访问了对象中不存在的属性时,编译器会及时给出提示。
const person = { name: "张三" };
person.age //"类型{name:string}"上不存在属性“age"
类型系统时代码变得更加可预测,能够给开发者更早发现潜在问题
for (let i = 0; i<5; i++) {
}
console.log(i) //编译器会捕获到错误:cannot find name i
当重复声明同名变量时,编译器会给出提示
let colors = ["red","green","blue"];
//无法重新声明块范围变量colors
let colors = ["red","green","blue"];
2. TypeScript 初体验
-
- 安装 TypeScript 编译器,用于将 TypeScript 代码编译为 JavaScript 代码
-
- 安装 axios 库,用于发送请求
-
- 新建 index.ts 文件,用于编写代码
-
- 将 TypeScript 代码编译为 JavaScript 代码并执行
第一步:安装 TypeScript 编译器,用于将 TypeScript 代码编译为 JavaScript 代码
# 全局安装typescript 编译器
npm install -g typescript
#通过查看typescript 编译器版本验证编译器是否安装成功
tsc -version
第二步:安装axios库,用于发送请求
#安装 axios用于发送请求
npm install axios
第三步:新建 index.ts 文件,用于编写代码,文件后缀为.ts
import axios from "axios";
axios.get("https://jsonplaceholder.typicode.com/todos/1").then((response) => {
console.log(response.data);
})
第四步:将 TypeScript代码编译为 JavaScript 代码并执行
#编译 index.ts 文件,编译后在同级目录下 会多出 index.js 文件,该文件存储的就是编译后的JavaScript 代码
tsc index.ts
#执行JavaScript 代码
node index.js
2.1 优化工作的流程
监控TypeScript 文件的变化,实现自动编译,自动执行代码
- 安装 nodemon、ts-node
- 创建应用启动脚本
- 通过应用启动脚本启动应用
#nodemon: 监听文件的变化,当TypeScript 文件内容发生变动后调用ts-node
# ts-node: 将 TypeScript 编译为 JavaScript 并执行
npm install -g nodemon ts-node
"scripts": {
"start": "nodemon index.ts"
}
npm start
tsc 与 ts-node 的主要区别 在于 tsc根据 您的tsconfig 编译所有文件。ts-node 从入口文件开始,并根据导入/导出逐步转译文件。
2.2 体验类型带来的好处
需求: 将任务ID,任务名称,任务是否完成分别输出到控制台中。
import axios from "axios";
axios.get("https://jsonplaceholder.typicode.com/todos/1").then((response)=> {
const todo = response.data;
const id = todo.ID;
const title = todo.Title;
const finished = todo.finished;
console.log(`
任务的ID是: ${id},
任务的名称是: ${title},
任务是否完成: ${finished}
`)
})
以上代码执行后,输出的结果都是undefined,发生了什么?
任务的ID是: undefined,
任务的名称是: undefined,
任务是否完成: undefined
通过查看得知,任务ID 对应的属性名称是 id, 任务名称对应的属性名称是title,任务是否完成对应的属性名称是completed,原来是属性名称写错了。
目前的问题是在书写代码的过程中并没有任何的错误tips,只有在代码运行后才会感知代码存在错误,这个问题应该怎么解决呢?
显示告知TypeScript 编译器response.data 中存储的数据类型,编译器会实时检测你写的代码是否符合类型上的要求。
以下代码展示是通过 TypeScript 约束对象中可以存在的属性,当访问了不存在的属性时编译器会实时进行提示。
import axios from "axios";
// interface 意为接口,可以约束对象中可以有哪些属性,约束对象中属性的类型
interface Todo {
id: number;
title:string;
completed:boolean;
}
axios.get("https://jsonplaceholder.typicode.com/todos/1").then((response)=>{
const todo = response.data as Todo;
const id = todo.ID //属性" id " 在类型Todo 上不存在。你是否指的是 "id"?
const title = todo.Title // 属性"Title" 在类型 Todo 上不存在,你是否指的是title?
const finished = todo.finished; //属性 finished 在类型 todo 上不存在
console.log(`
任务的ID 是: ${id},
任务的名称是: ${title},
任务是否结束: ${finished}
`)
})
以下代码展示的是通过TypeScript 约束函数参数的类型,调用函数时如果传入的参数类型错误,编译器会实时进行提示。
import axios from "axios";
interface Todo {
id:number;
title:string;
completed:boolean;
}
axios.get("https://jsonplaceholder.typicode.com/todos/1").then((response)=>{
const todo = response.data as Todo;
const id = todo.id;
const title = todo.title;
const completed = todo.completed;
logTodo(title,id,completed)
})
function logTodo(id:number,title:string,completed:boolean) {
console.log(`
任务的ID是: ${id},
任务的名称是: ${title},
任务是否结束: ${finished}
`);
}
3.TypeScript 基础类型
3.1.概述
在 TypeScript中,开发者可以通过类型注释对变量,参数,返回值的类型进行标注
| JavaScript | TypeScript |
|---|---|
| number | any |
| string | unknow |
| boolean | never |
| null | enum |
| undefined | tuple |
| object |
3.2 ts 基本数据类型
// 数值类型
let apples: number = 5;
// 字符串类型
let size: string = "big";
// 布尔值类型
let question: boolean = false;
如果修改的值不是 你定义的类型就会gg报错哦
// TS2322: Type 'string' is not assignable to type 'number'
// 类型 'string' 不能分配给类型为 'number'
apples = "5"; // ❎
// TS2322: Type 'number' is not assignable to type 'string'.
// 类型 'number' 不能分配给类型 'string'
size = 120; // ❎
// TS2322: Type 'string' is not assignable to type 'boolean'.
// 类型 'string' 不能分类给类型 'boolean'
question = "yes"; // ❎
3.3 any类型
any 类型顾名思义就是可以存储任何数据类型的值,例子如下
let anything: any = "hello ts";
anything = true;
anything = 3.14
anything = function() {};
anything = null
3.4 数组 Array
// 在没有为数组显示标注类型时,变量的初始值是一个空数组
// 此时刻数组中可以存储任何类型的值
// 虽然写法正确, 但丢失了 TypeScript 类型检查功能
// let colors = any[];
let colors = [];
colors[0] = 1;
colors[1] = "hello";
// 字符串数组
let colors: string[] = ["red","green","blue"];
// 数值数组
let numbers: number[] = [100,200,300];
// 布尔数组
let bools: boolean[] = [true,true,false]
const carMakers: string[][] = [["宝马","比亚迪"]]; //二维数组
// item: string
colors.forEach((item)=>{});
// let colors: string[]
colors[0]
3.5 元组 Tuples
在employee 数组中我们约定在数组中下标为0的位置存储员工姓名,在下标为1的位置存储员工的年龄。
let employee = ["张三",20];
employee[0] = 30;
employee[1] = "李四"
在这段代码中,没有约束每个数组元素对应的类型,导致在错误位置修改元素值时没有错误提示❌
那么元组的出现就可以把以上代码进行优化,元组一般用来存储一些特定顺序出现,且相关关联的数据,通过元组可以约束元素个数以及元素类型。
const employee: [string,number] = ["张三",20];
//不能将类型"number" 分配给类型 "string"
employee[0] = 30;
//不能将类型 "string" 分配给类型 "number"
employee[1] = "李四"
var bgColor: [number,number,number,number] = [0,255,255,0.5];
var employees: [number,string][] = [ [1,"Steve"],
[2,"Tom"],
];
3.6 枚举 Enum
枚举用于存储一组密切相关且有限的值,可以提升代码的可读性,可以限定值的范围,比如比赛的结果,考试的成绩,etc...
enum Sizes {
Small, // Small = 0
Medium, //Medium = 1
Large, //Large = 2
}
console.log(Sizes.Small)
enum Sizes {
Small = 1, //Small = 1
Medium, //2
Large, //3
}
console.log(Sizes.Small) // 1
//如果枚举值为非数值,则每个属性都必须进行初始化
enum Sizes {
Small = "s",
Medium = "m",
Large = "l",
}
conoel.log(Sizes.Small) //s
枚举编译后时 JavaScript中的对象
var Sizes;
(function (Sizes) {
Sizes["Small"] = "s";
Sizes["Medium"] = "m";
Sizes["Large"] = "l";
})(Sizes || (Sizes = {}));
在声明枚举类型时,如果使用const 关键字,TypeScript 编译器将输出更简洁的代码
const enum Sizes {
Small = "s",
Medium = "m",
Large = "l"
}
let selected = Sizes.Large;
console.log(selected)
//以下时编译结果
var selected = "l" /* Sizes.Large */;
console.log(selected);
// 枚举使用场景
enum Sizes {
Small = "s",
Medium = "m",
Large = "l",
}
let selected: Sizes = Sizes.Small;
function updateSize(size: Sizes) {
selected = size
}
updateSize(Sizes.larget)
| 场景 | 使用 | 不使用 |
|---|---|---|
| 消息的阅读状态 | YES | |
| 从1750年到现在的年份列表 | NO | |
| 菜单中饮料的种类 | YES | |
| 文章列表的所有标题 | NO | |
| 服务器端的电影分类 | NO | |
| 颜色选择器中的颜色 | YES |
3.7 函数Function
通过类型注释可以显示设置函数将要接受的参数类型,函数将要返回的值的类型
function add(a: number,b: number):number {
return a + b;
}
const add = (a: number,b: number): number => {
return a + b;
}
// TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.
sum(10,"20")
let logNumber: (n: number) => void;
logNumber = (m: number): void => {
console.log(m)
}
如果函数没有返回值,可以使用void 进行标注
function log(): void {}
TypeScript 编译器会检查实参的类型及参数数量是否正确。
function sum(a: number,b: number): number {
return a + b
}
sum(10,20,30) //Expected 2 arguments, but got 3.
TypeScript 编译器会检测函数是不是拥有正确的返回值
// TS2366: Function lacks ending return statement and return type does not include 'undefined'.
function sum(a: number): number {
if(a > 10) return a + 20
}
TypeScript 编译器会检测函数内部没有使用的变量
function log() {
//未使用的局部变量x
//移除未使用的局部变量 'x'
let x;
}
通过 ? 的方式设置可选参数,它的类型要么是它原本的类型要么就是undefined
//c ?: number | undefined
function sum(a: number,b:number,c?:number): number {
if(typeof c !== "undefined") {
return a + b + c
}
return a + b
}
sum(10,20)
通过参数默认值的方式设置可选参数,它的类型就是原本的类型
//c? number
function sum(a: number,b:number,c:number = 0) :number {
return a + b + c
}
sum(10,20)
在定义函数时,如果形参被定义为结构语法,则使用下面的方式给函数的形参设置类型
const logWeather = ({date,weather}: {date:Date,weather:string}) => {
console.log(date,weather)
}
const today = {
date: new Date(),
weather: "sunny"
}
logWeather(today)
const profile = {
age: 20,
coords: {
lat:0,
lng:15
}
}
const { age }: {age: number} = profile
const { coords: {lat,lng},}: {coords: {lat: number,lng:number} } = profile
3.8对象 Object
let pointL: {x: number; y: number} = { x:100,y: 200}
//对象字面量
let employee: { readyonly id: number} = {id: 1}
// TS2540: Cannot assign to 'id' because it is a read-only property.
// employee.id = 2;
// TS2741: Property 'name' is missing in type '{}' but required in type '{ name: string; }'.
// let person: { name: string } = {};
let people = {}
// TS2339: Property 'name' does not exist on type '{}'.
// people.name = "张三";
// age?: number | undefined
let student: {age? :number} = {}
student.age = 20;
内置对象,类本身可以作为类实例的类型
let date: Date = new Date();
//自定义类
//类 可以作为类实例的类型
class Car{}
let car: Car = new Car()
3.9类型推断
TypeScript编译器能根据一些简单的规则推断变量的类型,在没有显示设置变量类型的情况下,编译器将变量初始值的类型作为该变量的类型。
// let apples: number
let apples = 5
// let speed: string
let speed = "fast"
// let hasName: boolean
let hasName = true;
//let colors: string[]
let colors = ["red","green","blue"];
// let numbers: number[]
let numbers = [100,200,300]
//let bools: boolean[]
let bools = [true, true, false]
//let anything: any[]
let anything = []
// let point: {x: number,y: number}
let point = { x:100,y:200 };
TypeScript 编译器会试图推断函数返回值的类型。
注意:在使用函数返回值类型推断是,在编写函数内部代码时就回市区类型检测功能,所以函数返回值类型推荐明确表明指定,如果函数的返回值是undefined,可以指定函数的返回值为 void
//const add:(a: number,b: number) => number
const add = (a: number,b:number) => {
return a + b
}
//const add: (a: number,b:number) => void
const add = (a: number,b: number) => {}
//const add: (a: number,b: string) => string
const add = ( a: number, b: string) => {
return a + b
}
//const add: () => string
const add = () => {
return "a"
}
// const find: (name:string) => string | boolean
const find = (name:string) => {
if( name ) {
return name;
} else {
return false
}
}
在TypeScript 编译器可以推断出变量类型的情况下,开发者不需要显示编写类型注释,也就是说只有在TypeScript 不能正确推断变量类型的情况下开发者才需要编写类型注释,那么哪些情况下 ts 编译器是不能正确推断出变量的类型呢?
-
如果变量声明后没有被立即出实话,TypeScripts 编译器不能正确的推断出它的类型。
// 此时 TypeScript 编译器认为它是 Any类型,即在该变量中可以存储任意类型的数据 // 该变量失去了 TypeScript 中的类型检查功能 // let anything : any let anything; anything = 12; anything = "hello"; anything = truelet colors = ["red","green","blue"]; // let foundColor: any // 解决办法就是要么设置初始值,要么显示指定变量类型 let foundColor; let foundColor: boolean; for (let i = 0; i< colors.length; i++) { if (colors[i] === "green") { foundColor = true } }-
当调用的函数返回值为Any 类型时,我们应该使用类型注释显示声明它的类型。
// let json: string let json = '{"name":"张三"}' // let person: any => let person: {name:string} let person = JSON.parse(json) -
当变量可能有多个类型的值时。
// 需求: 在数组中查找大于 0 的数值, 如果找到将该值赋值给变量 target, 如果没有找到, 将 false 赋值给变量 target let numbers = [-10, -1, 20]; let target = false; for (let i = 0; i < numbers.length; i++) { if (numbers[i] > 0) { // 不能将类型"number"分配给类型"boolean" target = numbers[i]; } }// 解决方法 let target: boolean | number = false -
函数的参数必须设置类型,TypeScript 并不能推断函数参数的类型。
// TS7006: Parameter 'a' implicitly has an 'any' type function sum(a, b) {}
-