学习视频1:coderwhy
学习视频2:尚硅谷
文章目录
- TypeScript 学习笔记
- 概述
- TypeScript 开发环境搭建
- 类型注解
- 类型推断
- 数据类型
- JS的7个原始类型
- Array数组
- object、Object 和 {}
- 1.可选属性 ?
- 2.type 类型别名 和 接口interface
- 函数
- TS类型: any类型 | unknow类型
- TS类型: void类型
- TS类型:never类型 (几乎不用)
- TS类型:Tuple(元组)
- 语法细节
- 1.联合类型 | 和交叉类型
- 2.type和interface
- 3.类型断言和非空断言
- 4.字面量类型和类型缩小
- 5.函数的类型和函数签名
- 6.函数的重载和this类型
TypeScript 学习笔记
概述
JavaScript的变量类型相当于是动态类型,可以跟随着赋值的改变而类型改变,函数的参数也没有设定类型,所以在定位错误以及安全性上不太够。
说明
1.TS不能被JS解析器直接执行,需要编译成JS执行
2.即使TS编译出错也可以编译成JS
1.TypeScript是什么?
TypeScript 是类型安全的JavaScript(拥有类型的JavaScript超集),JavaScript是弱类型, 很多错误只有在运行时才会被发现,而TypeScript提供了一套静态检测机制, 在编译时就发现错误
2.TypeScript的好处是什么?
1.支持强类型
2.类型注解:通过类型注解来增加编译时静态类型检查
3.增加了特性:泛型、接口、抽象类等
TypeScript 开发环境搭建
安装TS解析器 :解析器使用nodejs写的 —> 先安装nodejs我node已经安装好啦,直接安装TypeScript
1.使用npm全局安装TypeScript
npm i -g typescript
2.检查是否安装成功
tsc --version
3.创建一个ts文件:后缀以ts结尾
使用tsc对ts文件进行编译,进入到该文件的命令行,使用tsc 文件名
进行编译
tsc test.ts
TS运行效果查看
1.通过tsc编译TS代码到JS代码
2.在浏览器环境或者node环境下运行JS代码
简化版本
- 通过webpack 配置本地的TS编译环境和开启一个本地服务,可以直接运行在浏览器上(ts-loader)
- 通过ts-node库,为TS的运行提供执行环境
# 安装ts-node
npm install ts-node -g
# 按照ts-node依赖包tslib @types/node
npm install tslib @types/node - g
# node上运行js
node xxx.js
# node上运行ts
ts-node xxx.ts
类型注解
类型注解:主动告诉ts是什么类型
语法:变量名:数据类型
说明
1.冒号后面的数据类型被称为类型注解★
2.声明了类型后TS就会进行类型检测
类型推断
类型推断:声明一个变量时,如果有直接赋值,会根据赋值的类型推导出标变量的类型注解。
说明
1.声明变量如果不指定类型,也不赋值,则TS解析器会自动判断变量的类型为any
2.从右到左推断
3.let进行类型推导,推导出来是通用类型
const类型推导,推导出来是字面量类型
const height = 1.88 //1.88为heigth的类型,1.88是字面量类型
const height:1.88 //等价于
数据类型
- JS数据类型: 7个原始类型 (string,number,boolean,undefined,null,bigint,symbol) + Array + Object
- TS新增类型:
any
+unknow
+void
+never
总结
1.默认情况下 null
和 undefined
是所有类型的子类型,这两种类型可以赋值给任意类型的变量
4.never
类型是任何类型的子类型,也可以赋值给任何类型的变量
2. unknown
是 顶级类型,任何类型的值(never除外)都可以赋值给该类型的变量
3. any
是顶级类型,任何类型的值(never除外)都可以赋值给该类型的变量,也是所有类型的子类型,any相当于关闭类型检测
JS的7个原始类型
let str: string = "jimmy";
let num: number = 24;
let bool: boolean = false;
let u: undefined = undefined;
let n: null = null;
let big: bigint = 100n;
let sym: symbol = Symbol("me");
说明
1.默认情况下 null
和 undefined
是所有类型的子类型。 可以把 null 和 undefined 赋值给其他类型。
如果你在tsconfig.json指定了"strictNullChecks":true ,null 和 undefined 只能赋值给 void 和它们各自的类型。
2.String是JavaScript中字符串包装类
Array数组
//明确指定数组的类型注解写法1
let arr:string[] = ["1","2"];
//明确指定数组的类型注解写法2 泛型写法
let arr2:Array<string> = ["1","2"];
object、Object 和 {}
语法:{属性名:属性值,属性名:属性值....}
说明
1.属性个数名字必须一模一样,不能多不能少
2.分割符分号和逗号可以,换行可以省略分号,因为JS中换行会自动添加分号
3.object、Object 和 {}
Object
代表所有拥有toString
、hasOwnProperty
方法的类型,所有原始类型、非原始类型都可以赋给 Object。在严格模式下,null 和 undefined 类型也不能赋给 Object。{}
等价于Object
object
则表示非原始类型
let info: object = {
name: 'why',
age: 18
}
info = [1,2,3]; //非原始类型
console.log(info);
info = 123; //报错
4.类型不注解,默认为any
以下写法,在实际开发中并不会使用,因为object并不清楚里面的属性是什么类型,获取到对象里的属性会报错。
//不使用
let info: object = {
name: 'why',
age: 18
}
console.log(info['age']) //报错
/*
写法1
let info: {
name:string
age:number
}
写法2
let info: {name:string;age:number}
写法3
let info: {name:string,age:number}
*/
let info: {
name:string
age:number
} = {
name: 'why',
age: 18
}
1.可选属性 ?
如果某一属性不确定,可以使用?标识该属性可选
语法:{属性名:属性值,属性名?:属性值
}
2.type 类型别名 和 接口interface
type 用于定义类型别名 (type alias)
//使用type声明对象
type IDType = string | number | boolean
//分号和逗号可以
type PointType = {x: number,y: number}
type PointType = {x: number;y: number}
type PointType = {//换行可以省略分号,因为js中换行会自动添加分号
x: number
y: number
}
接口可以看成规则,实现接口就必须满足接口设置的规则
语法 interface 接口名
//使用借口来声明对象
interface PointType{
x:number
y:number
}
interface PointType{
z:number
}
//多次声明需要都满足
const obj:myInterface = {//obj对象必须满足接口的规则有name和age
x:1,
y:2,
z:3
}
类型别名与接口的区别
- | 相同点 | 不同点 |
别名 | 1.类型别名和接口非常相似,在定义对象类型时,大部分时候可以任意选择使用。 2.接口中几乎所有的特性都可以在type中使用 | 1.使用范围更广 2.不允许同名声明两次(报错) |
接口 | 1.只能声明对象 2.可以多次声明同一个接口名称,属性叠加 |
函数
function add(x: number, y: number): void {
x + y;
}
1.匿名函数 - 大多数时候不需要类型注解
当一个函数出现在TS可以确定该函数会被如何调用的地方时,该函数的参数会自动指定类型,最好不要加类型注解
const names = ['abc', 'cba', 'nba']
// 根据上下文环境推导出来的,这个时候可以不添加类型注解
// 上下文中的函数,可以不添加类型注解
names.forEach(function (item,index,arr) {
console.log(item,index,arr)
})
这是因为TypeScript会根据forEach函数的类型以及数组的类型推断出item的类型;
这个过程称之为上下文类型(contextual typing),因为函数执行的上下文可以帮助确定参数和返回值的类型;
TS类型: any类型 | unknow类型
1.在 TypeScript 中,任何类型都可以被归为 any 类型,因此any 类型也是类型系统的顶级类型。
2.变量如果在声明的时候,未指定其类型,会被识别为任意值类型。
3.unknown
与any
一样,所有类型都可以分配给unknown
,都表示不清楚是类型。
unknown 是 top type (任何类型都可以赋值给unknow类型) , 而 any 既是 top type, 又是 bottom type (任何类型都可赋值给any类型的变量,any类型可以赋值给任何类型) 。
区别 | 赋值 | 描述 | |
---|---|---|---|
any | any 上访问任何属性都是允许的,也允许调用任何方法 | any 类型可以赋值给任意类型 | any相当于关闭类型检验 |
unknow | 默认情况下unknow 类型上不能访问属性和调用方法(执行任何操作?),必须进行类型校验(缩小)才可以执行对应操作 | unknow 类型只能赋值给 any 和 unknow 类型 | unknow是更加安全的any,会进行类型检测 |
let foo:unknown = 'aaa'//合法
foo = 123 //合法
console.log(foo);//合法
console.log(foo.length); //非法
//类型缩小
if(typeof foo ==="string"){
console.log(foo.length); //合法
}
TS类型: void类型
当函数没有返回值,则返回void类型
function foo (num1:number,num2:number):void{
console.log(num1+num2)
return undefined
//null也可以
return null
}
/*
foo的类型是()=>void 表示是一个返回void的函数类型
const类型推导,推导出来是字面量类型
const height = 1.88 //1.88为heigth的类型,1.88是字面量类型
const height:1.88 //等价于
*/
const foo = () =>{}
//等价于
type FooType = () => void
const foo:FooType = ()=>{}
说明
1.可以返回null和undefined,因为默认情况下null
和undefined
是所有类型的子类型。
2.方法没有返回值将得到undefined,但是需要定义成void类型,而不是undefined类型,否则将报错。
3.当基于上下文的类型推导推导出返回类型为void的时候,并不会强制函数一定不会返回内容。(了解)
let names:Array<string> = ['arr1','arr2']
names.forEach((item,index,arr)=>{
return 123;//没有意义但是不会报错
})
TS类型:never类型 (几乎不用)
开发中很少使用never类型
never
表示永不存在的值
①函数抛出异常,函数不会执行完毕并返回
②函数中执行无限循环的代码,使得程序永远无法运行到函数返回值那一步,永不存在返回。
新版本已经修改,类型推导出来是void
function foo(){
while (true) {}
}
function bar(){
throw new Error()
}
never的使用场景
//封装工具/框架
function handleMessage(message: string | number ) {
switch (typeof message) {
case 'string':
console.log('string处理方式处理message')
break
case 'number':
console.log('number处理方式处理message')
break
default:
const check: never = message //这一步永远来不到
}
}
handleMessage('abc')
handleMessage(123)
//另外一个人调用这个函数传入布尔类型,函数定义参数部分添加boolean类型,check:never位置报错,就会发现case少了一个布尔类型
TS类型:Tuple(元组)
元组类型表示一个已知元素数量和类型的数组(固定长度和类型的数组),各元素的类型不必相同。
数组中通常建议存放相同类型的元素,不同类型的元素是不推荐放在数组中。如果不同类型放在数组中,取值时并不清楚每个元素的具体类型。
使用元组类型的好处
1.元组数据结构中可以存放不同的数据类型,取出来的item也有明确的类型
2.减少对象key的使用
let x: [string, number] = ['hello', 10];
console.log(x[0])
//类型推导:(string|numbner)[] ,取值并不清楚每一个元素是什么类型
let y = ['hello',10]
使用场景:当函数需要返回多个值的时候
function useState<T>(state: T) {
// T 泛型
let currentState = state
const changeState = (newState: T) => {
currentState = newState
}
const tupple: [T, (newState: T) => void] = [currentState, changeState]
return tupple //返回值为[参数,函数]
}
const [
counter, // number
setCounter // (newState: number) => void
] = useState(10)
setCounter(1000)
const [
title, // string
setTitle // (newState: string) => void
] = useState('abc')
const [
flag, // boolean
setFlag // (newState: boolean) => void
] = useState(true)
语法细节
1.联合类型 | 和交叉类型
联合类型:取值可以为多种类型中的一种,使用 |
分隔每个类型
let myFavoriteNumber: string | number;
myFavoriteNumber = 'seven'; // OK
myFavoriteNumber = 7; // OK
说明
1.联合类型中的每一个类型被称之为联合成员(union’s members)
2.通常配合缩小联合
一起使用
function printId(id:number|string){
if(typeof id === 'string'){
//缩小范围
}else{
}
}
2.type和interface
type 用于定义类型别名 (type alias)
type IDType = string | number | boolean
//分号和逗号可以
type PointType = {x: number,y: number}
type PointType = {x: number;y: number}
type PointType = {//换行可以省略分号,因为js中换行会自动添加分号
x: number
y: number
}
接口可以看成规则,实现接口就必须满足接口设置的规则
语法 interface 接口名
接口作为类型声明
interface myInterface{//定义接口的规则
name:string,
age:number,
?sex:string //可选属性
}
const obj:myInterface = {//obj对象必须满足接口的规则有name和age
name:'xxx',
age:111
}