ts学习笔记

编译TypeScript

浏览器不能直接运行ts代码,需要编译为js再交由浏览器解析执行

1.命令行编译
第一步:全局安装

npm i typescript -g

第二步:使用命令编译目标文件

tsc demo.ts

2.自动化编译
第一步:初始化ts编译控制文件

tsc --init
/*
1.在跟目录下会生成一个tsconfig.json配置文件,其中包含多种编译配置
2.默认编译的js版本是es7
*/

第二步:监测目录中.ts文件的变化

tsc --watch或tsc -w

类型声明

使用:来对变量或函数形参,进行类型声明

let a: string //变量a只能存储字符串
let b: number //存储数值
let c: boolean //存储布尔值
function demo(x:number,y:number):number{//x,y,返回值都必须是数字
	return x+y
}

Ts中的数据类型

1.包含所有的js类型(string,number,boolean,null,undefined,bigint,symbol,object)
2.六个新类型(any,unknown,never,void,tuple,enum)
3.两个用于自定义类型的方式(type,interface)
注意点:

在js中的这些内置构造函数:Number,String,Boolean,用于创建对应的包装对象,在日常开发时很少使用,在ts中也是一样的,所以在ts中进行类型声明时,通常都是用小写的number,string,boolean

Ts中常用类型及语法

1.any:任意类型,一旦将变量类型限制为any,意味着放弃了对该变量的类型检查

// 明确的表示a的类型是 any —— 【显式的any】
let a: any 
// 以下对a的赋值,均无警告
a = 100
a = '你好'
a = false

// 没有明确的表示b的类型是any,但TS主动推断出来b是any —— 隐式的any
let b 
//以下对b的赋值,均无警告
b = 100
b = '你好'
b = false

/* 注意点:any类型的变量,可以赋值给任意类型的变量 */
let c:any
c = 9

let x: string
x = c // 无警告

2.unknown:未知类型,适用于:期初不确定数据的具体类型,要后期才能确定

1.unknown可以理解为一个类型安全的any

let a: unknown
//一下对a的赋值,均符合规范
a = 100
a = false
a = '你好'
//设置x的类型为string
let x:string
x = a//警告:不能将类型unknown分配给类型string

2.unknown会强制开发者在使用之前进行类型检查,从而提供更强的类型安全性

let x:string
let a:unknown
a = 'hello'
//把变量a的值付给变量x
x = a //警告:a的类型是unknown
/*解决方式*/
//第一种:加类型判断
if(typeof a ==='string'){
	x = a
	console.log(x)
}
//第二种方式:加断言
x = a as string
x = <string>a

3.读取any类型数据的任何属性都不会报错,而unknown正好与之相反

let str1:string
str1 = 'hello'
str1.toUpperCase()//无警告

let set2:any
set2= 'hello'
set2.toUpperCase()//无警告

let set3:unknown
set3= 'hello'
set3.toUpperCase()//警告:str3的类型为未知
//使用断言强制制定str3的类型为string
<string>set3.toUpperCase()//无警告

3.never:任何值都不是,即:不能有值,例如undefined,null,‘’,0都不行

1.几乎不用never去直接限制变量,因为没有意义

//指定a的类型为never,那就意味着a以后不能存任何的数据了
let a:never
//以下对a的所有赋值都会有警告
a = 1
a = true
a = undefined
a = null

2.never一般是ts主动推断出来的

//指定a的类型为string
let a:string
a = 'hello'
if(typeof a === 'string'){
	console.log(a.toUpperCase())
}else{
	console.log(a)//ts会推断出此处的a是nerve,因为没有任何一个值符合此处的逻辑
}

3.never也可用于限制函数的返回

//限制throwError函数不需要有任何返回值,任何只都不行,包括undefined,null
function throwError(str:string):never{
	throw new Error('程序异常退出:'+str)
}

4.void:函数不返回任何值,调用者也不应该依赖其返回值进行任何操作

1.void通常用于函数返回值声明

function logMessage(msg:string):void{
	console.log(msg)
}
logMessage('你好')
/*
注意:编码者没有编写return指定函数返回值,所以logMessage函数是没有显式返回值的,但会有一个隐式返回值undefined,虽然函数返回类型为void,但也是可以接受undefined的
*/

2.以下写法均符合规范

function logMessage(msg:string):void{
	console.log(msg)
}
function logMessage(msg:string):void{
	console.log(msg)
	return
}
function logMessage(msg:string):void{
	console.log(msg)
	return undefined
}

3.限制函数返回值时,是不是undefined和void就没有区别呢?-----有区别.因为 返回值类型为void的函数,调用者不应该依赖其返回值进行任何操作

function logMessage(msg:string):void{
	console.log(msg)
}
let result = logMessage('你好')
if(result){//这里会报错,无法测试void类型的表达式的真实性
	console.log('logMessage有返回值')
}


5.object:时间开发中用的相对较少,因为范围太大
1.object(小写):所有非原始类型,可存储:对象.函数,数组等,由于限制的范围比较宽泛,在实际开发中使用的相对较少

let a:object //a的值可以是任何非原始类型,包括:对象,函数,数组等
//以下代码,是将非原始类型赋给a,所以均符合要求
a = {}
a = {name:'zs'}
a = [1,2,3,4,5]
a = function(){}
a = new String('123')
class Person{}
a = new Person()
//以下代码,是将原始类型赋给a,有警告
a = 1         // 警告:不能将类型“number”分配给类型“object”
a = true      // 警告:不能将类型“boolean”分配给类型“object”
a = '你好'    // 警告:不能将类型“string”分配给类型“object” 
a = null      // 警告:不能将类型“null”分配给类型“object”
a = undefined // 警告:不能将类型“undefined”分配给类型“object”

2.Object(大写):所有可以调用Object方法的类型(除了undefined和null的任何值)由于限制的范围实在太大,所以实际开发中使用频率极低

let b:Object //b的值必须是Object的实例对象(除去undefined和null的任何值)

// 以下代码,均无警告,因为给a赋的值,都是Object的实例对象
b = {}
b = {name:'张三'}
b = [1,3,5,7,9]
b = function(){}
b = new String('123')
class Person {}
b = new Person()
b = 1  			// 1不是Object的实例对象,但其包装对象是Object的实例
b = true  	// truue不是Object的实例对象,但其包装对象是Object的实例
b = '你好'	// “你好”不是Object的实例对象,但其包装对象是Object的实例

// 以下代码均有警告
b = null      // 警告:不能将类型“null”分配给类型“Object”
b = undefined // 警告:不能将类型“undefined”分配给类型“Object”

3.声明对象类型

1.实际开发中,限制一般对象,通常使用以下形式

//限制person1对象必须有name属性,age为可选属性
let person1:{name:string,age?:number}
//含义同上,也能用分号做分隔
let person2:{name:string;age?:number}
//含义同上,能用换行做分隔
let person3:{
	name:string
	age?:number
}

//如下赋值均可以
person1 = {name:'李四',age:18}
person2 = {name:'张三'}

//如下赋值不合法,因为person3的类型限制中,没有对gender属性的说明
person3 = {name:'王五',gender:'男'}

2.索引签名:允许定义对象可以具有任意数量的属性,这些属性的键和类型是可变的,常用于:描述类型不确定的属性

//限制person对象必须有name属性,可选age属性但值必须是数字,同时可以有任意数量,任意类型的其他属性
let person:{
	name:sting
	age?:number
	[key:sting]:any //索引签名,完全可以不用key这个单词,换成其他的也可以
}
//合法赋值
person = {
	name:'张三',
	age:18,
	gender:'男'
}

4.声明函数类型

let count:(a:number,b:number) => number
count = function(x,y){
	return x+y
}
/*
ts中的=>在函数类型声明时表示函数类型,描述其参数类型和返回类型
js中的=>是一种定义函数的语法,是具体的函数实现
*/

5.声明数组类型

let arr1:string[]
let arr2:Array<string>

arr1 = ['a','b','c']
arr2 = ['a','b']
//上述代码中的Array<string>属于泛型

6.tuple:(元祖)是一种特殊的数组类型,可以存储固定数量的元素,并且每个元素的类型是已知的且可以不同.元祖用于精确描述已组值的类型, ?表示可选元素

//第一个元素必须是string类型,第二个元素必须是number类型
let arr1:[string,number]
//第一个元素必须是number类型,第二个元素是可选地,如果存在,必须是boolean类型
let arr2:[string,boolean?]
//第一个元素必须是string类型,后面的元素可以是任意数量的string类型
let arr3:[number,...string[]]

// 可以赋值
arr1 = ['hello',123]
arr2 = [100,false]
arr2 = [200]
arr3 = [100,'hello','world']
arr3 = [100]

// 不可以赋值,arr1声明时是两个元素,赋值的是三个
arr1 = ['hello',123,false]

7.enum:(枚举)可以定义一组命名常量,他能增强代码的可读性

如下代码的功能是:根据调用walk时传入的不同参数,执行不同的逻辑,存在的问题是调用walk时传参时没有任何提示,编码者很容易写错字符串内容;并且用于判断逻辑的up、down、left、right是连续且相关的一组值,那此时就特别适合使用 枚举(enum)。

function walk(str:string) {
  if (str === 'up') {
    console.log("向【上】走");
  } else if (str === 'down') {
    console.log("向【下】走");
  } else if (str === 'left') {
    console.log("向【左】走");
  } else if (str === 'right') {
    console.log("向【右】走");
  } else {
    console.log("未知方向");
  }
}

walk('up')
walk('down')
walk('left')
walk('right')

1.数字枚举:最常见的枚举类型,其成员的值会自动递增,其数字枚举还具备反向映射的特点,在下面代码的打印中,不难发现:可以通过值来获取对应的枚举成员名称 。

enum Direction{
	Up,
	Down,
	Left,
	Right
}
console.log(Direction) // 打印Direction会看到如下内容
/* 
  {
    0:'Up', 
    1:'Down', 
    2:'Left', 
    3:'Right', 
    Up:0, 
    Down:1, 
    Left:2,
    Right:3
  } 
*/

// 反向映射
console.log(Direction.Up)
console.log(Direction[0])

// 此行代码报错,枚举中的属性是只读的
Direction.Up = 'shang'

也可以指定枚举成员的初始值,其后的成员值会自动递增

enum Direction {
  Up = 6,
  Down,
  Left,
  Right
}

console.log(Direction.Up); // 输出: 6
console.log(Direction.Down); // 输出: 7

使用数字枚举完成刚才walk函数中的逻辑,此时我们发现: 代码更加直观易读,而且类型安全,同时也更易于维护。

enum Direction {
  Up,
  Down,
  Left,
  Right,
}

function walk(n: Direction) {
  if (n === Direction.Up) {
    console.log("向【上】走");
  } else if (n === Direction.Down) {
    console.log("向【下】走");
  } else if (n === Direction.Left) {
    console.log("向【左】走");
  } else if (n === Direction.Right) {
    console.log("向【右】走");
  } else {
    console.log("未知方向");
  }
}

walk(Direction.Up)
walk(Direction.Down)

2.字符串枚举:枚举成员的值是字符串

enum Direction {
  Up = "up",
  Down = "down",
  Left = "left",
  Right = "right"
}

let dir: Direction = Direction.Up;
console.log(dir); // 输出: "up"

3.常量枚举

8.type:可以为任意类型创建别名,让代码更简洁,可读性更强,同时能更方便地进行类型复用和扩展
1.基本用法:类型别名使用type关键字定义,type后跟类型名称,例如下面代码中num是类型别名

type num = number;
let price:num
price = 100

2.联合类型:是一种高级类型,他表示一个值可以是几种不同类型之一

type Status = number | string
type Gender = '男'|'女'
function printStatus(status:Status){
	console.log(status)
}
function logGender(str:Gender){
	console.log(str)
}
printStatus(404)
printStatus('200')
printStatus('501');

logGender('男')
logGender('女')

3.交叉类型:允许将多个类型合并为一个类型.合并后的类型将拥有所有被合并类型的成员.交叉类型通常用于对象类型

//面积
type Area = {
	height:number;//高
	width:number;//宽
}
//地址
type Address = {
	num:number;//楼号
	cell:number;//单元号
	room:string;//房间号
}
//定义类型House,且House是Area和Address组成的交叉类型
type House = Area&Address
const house:House={
	  height: 180,
	  width: 75,
	  num: 6,
	  cell: 3,
	  room: '702'
}
  • 8
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值