TypeScript学习03-TypeScript基础语法

3、TypeScript基础语法

3.1、变量声明

我们已经多次强调、在TypeScript中定义变量需要指定标识符的类型、完整的格式如下

var/let/const 标识符:数据类型=赋值;

声明了类型后TypeScript就会进行类型检测,声明的类型可以称之为类型注解(Type Annotation)

比如我们声明一个message,完整的写法如下:

//注意:这里的string是小写的,和String是有区别的

//string是TypeScript中定义的字符串类型,String是ECMAScript中定义的一个类    

let message:string="Hello World"

如果我们给message赋值其他类型的值,那么就会报错

image-20231217124355024

3.2、声明变量的关键字

在TypeScript定义变量(标识符)和ES6之后一致,可以使用varletconst来定义。

var myname:string="why";
let myage:number="20";
const myheight:number=1.88;

当然,在tslint中并不推荐使用var来声明变量:

可见,在TypeScript中并不建议再使用var关键字了,主要原因和ES6升级后letvar的区别是一样的,var是没有块级作用域的,会引起很多的问题,这里不再展开探讨

image-20231217125107607

3.3、标识符的类型推导

在开发中时、为方便起见我们并不会在声明每一个变量时都写上对应的数据类型,我们更希望可以通过TypeScript本身的特性帮助我们推断出对应的变量类型。

那什么是类型推导?

声明一个标识符时,如果有直接的进行赋值、会根据赋值的类型推导出标识符的类型注解,这个过程被称之为类型推导

Let进行类型推导,推导出来的通用类型

const进行类型推导,推导出来的是字面量类型,某一个值也可以被当成标识符的类型

什么场景下使用?

1、声明变量并初始化时,2、决定函数的返回值时

// 变量 age 的类型被自动推断为:number
let age = 18

// 函数返回值的类型被自动推断为:number
function add(num1: number, num2: number) {
  return num1 + num2
}

类型推断的好处?

由于类型推论的存在,这些地方,类型注解可以省略不写

能省略类型注解的地方就省略偷懒,充分利用TS类型推论的能力,提升开发效率)

如果不知道类型,可以通过鼠标放在变量名称上,利用VSCode 的提示来查看类型

官方的说法?

在这里插入图片描述

记住、我们并不总是需要编写显式的类型注释,在许多情况下,TypeScript甚至可以推断(或者算出)为我们提供的类型,即使我们省略它们

3.4、JavaScriptTypeScript的数据类型

我们常说、TypeScript是JavaScript的一个超集

image-20231217132441120

3.5、number类型

数字类型是我们开发中经常使用的类型,TypeScriptJavaScript一样,不区分整数类型(int)和浮点型(double),统一为number类型

let num =100
num=20
num=6.6

学习过ES6应该知道,ES6新增了二进制和八进制的表示方法,而TypeScript也是支持二进制、八进制、十六进制的表示

num=100;    //十进制
num=0b110;  //二进制
num=0o555;  //八进制
num=0xf23;  //十六进制

3.6、boolean类型

boolean类型只有两个取值:true和false,非常简单

//boolean类型的表示
let flag:boolean=true;
flag=false;
flag=20>30;

3.7、string类型

string类型是字符串类型,可以使用单引号或者双引号表示:

image-20231218104409183

同时也支持Es6的模版字符串来拼接变量和字符串

image-20231217133628653

3.8、Array类型

数组类型的定义也非常的简单,有两种方式

//正常的写法
const names:string[]=["abc","cba","cba"]
//泛型写法    
const name2:Array<string> =["abc","cba","mba"]

nases.push("why")
name2.push("why")   

如果添加其他类型到数组中,那么会报错:

在这里插入图片描述

3.9、Object类型

//1、没有经过类型推导的Ts写法
let info1:{
  name:string
  age:Number
  height:Number
} = {
  name: "why",
  age: 18,
  height: 1.88
}
console.log(info.name)
console.log(info.age)

//2、经过类型推导的简写形式
let info2 = {
  name: "why",
  age: 18,
  height: 1.88
}
console.log(info.name)
console.log(info.age)



//3、Type关键字的使用
type InfoType={
  name:String
  age:number
}

let infoType:InfoType={
  name:"侯茂昌",
  age:18
}

//4、直接告诉他是一个对象类型
//但是这样做非常的不好、这个的写法从ts角度来说他不是一个错误的ts语法
//但是从开发的角度并不会这样做、因为当你给一个东西指定为一个object类型的时候
//意味这object表示是一个空对象类型
let  infoObject:object={
  name:"why",
  age:18
}
//获取值
console.log(infoObject.name)  //会报错
//获取值
console.log(infoObject["name"]) //会报错
//设置值
infoObject["name"]="hmc"  //会报错

export {}

3.1、Symbol类型

在Es5当中、如果我们是不可以在对象中添加相同的属性名称的,比如以下的做法

const person={
    identity:"程序员"
    identity:"老师"
}

通常我们 的做法是定义两个不同的属性名字、比如identity1、identity2

但是我们也可以通过symbol来定义相同的名称、因为Symbol函数返回的是不同的值

const s1:symbol=Symbol("title")
const s2:symbol=Symbol("title")
const:person={
    [s1]:"程序员"
    [s2]:"老师"
}

3.2、null和undefined类型

在JavaScript中,undefined和null是两个基本数据类型

在TypeScript中、他们各自的类型也是undefined和null,也就意味这他们既是实际的值、也是自己的类型

let n:null=null
let u:undefined=undefined

3.3、函数的参数类型

函数是JavaScript非常重要的组成部分,TypeScript允许我们指定函数的参数和返回值的类型

参数的类型注解

声明函数时,可以在每个参数后添加类型注解,以声明函数接受的参数类型:

function greet(name:string){
    console.log("Hello"+name.toUpperCase())
}

greet(123)
    
greet("abc","cba")

3.4、函数的返回值类型

我们也可以添加返回值的类型注解,这个注解出现在函数列表的后面:

// 在定义一个TypeScript中的函数时
// 返回值类型可以明确的指定, 也可以自动进行类型推导
function sum(num1: number, num2: number): number {
  return num1 + num2
}

和变量的类型注解一样,我们通常情况下不需要返回类型注解,因为TypeScript会根据 return 返回值推断函数的返回类型:

某些第三方库处于方便理解,会明确指定返回类型,看个人喜好

3.5、匿名函数的参数

什么是匿名函数?

结论:一个函数作为一个参数传递给了另一个参数

匿名函数是否需要添加类型注解呢?

结论:最好不要加类型注解

·如下代码

const names=["abc","cba","nba"]
//item,index.arr最好不要添加类型注解、有可能会一不小心添加错了、他自己会根据上下文进行类型推导
names.forEach(funcation(item,index,arr)){
    console.log(item,index,arr)
})
const names=["abc","cba","nba"]
names.forEach(item=>{
    console.log(item.toUppercase())
})

我们并没有指定item的类型,但是item是一个string类型

这是因为TypeScript会根据forEach函数的类型以及数组的类型推断出item的类型

这个过程称之为上下文类型(contextual typing,因为函数执行的上下文可以帮助确定参数和返回值的类型;

3.6、对象类型

如果我们希望限定一个函数接受的参数是一个对象,这个时候要如何限定呢?

function printCoordinate(point:{x:number,y:number}){
    console.log("x坐标",ponint.x)
    console.log("y坐标",ponint.y)
}

printCoordinate({x:10,y:30})

上述代码,我们使用了一个对象来作为类型

在对象中我们可以添加属性,如{ x:number , y:number},并且告知TypeScript该属性需要是什么类型,属性之间可以使用 , 或者 ; 来分割,最后一个分隔符是可选的;每个属性的类型部分也是可选的,如果不指定,那么就是any类型;

3.7、对象类型参数的可选类型

对象类型也可以指定哪些属性是可选的,可以在属性的后面添加一个?

function printCoordinate(point:{x:number,y:number,z?:number}){
    console.log("x坐标:",point.x);
    console.log("y坐标:",point.y)
    if(ponit.z){
        console.log("z坐标:",point.z)
    }    
}

printCoordinate({x:10,y:30})
printCoordinate({x:20,y:30,z:40})    

3.8、any类型

在某些情况下我们无法确定一个变量的类型、并且可能会发生一些变化、这个时候我们可以使用any类型,有点类似于Dart语言中的dynamic类型

any类型有点像一种讨巧的TypeScript手段

我们可以对any类型的变量进行任何操作、包括获取不存在的方法、属性

我们可以给一个any类型的变量赋值任何的值、比如 数字、字符串、boolean的值

let a:any="why"
a=123
a=true
    
const aArray : any[]={"why",18,1.88}

如果对于某些情况的处理过于繁琐不希望添加规定的类型注解,或者引入一些第三方库时,缺失了类型注解,这个时候我们可以使用any

包括在Vue源码中,也会使用到any来进行某些类型的适配

3.9、unknown类型

在TypeScript中,unknown类型是一种非常特殊的顶级类型,它表示的是所有类型的联合,但与any类型不同的是,unknown提供了更强的类型安全性。当一个值被标记为unknown时,编译器会严格限制对该值的操作:

村夫解释:

nnknown是TypeScript中比较特殊的一种类型、他通常用于描述类型不确定的变量、

跟any有点类似,但是unknown类型上做任何事情都是不合法的?

直接访问其属性报错

不能直接访问其属性或方法,因为编译器无法确定未知类型的对象具体包含哪些属性和方法。

let value: unknown = { message: "Hello" };
// 错误:Property 'message' does not exist on type 'unknown'.
console.log(value.message);

不能将其作为函数参数传递给需要特定类型的位置,除非目标参数接受unknown或者使用类型断言转换成兼容类型。

使用typeof 或者instanceof细化类型 、进行类型缩小

function printMessage(message: string) {
    console.log(message);
}
// 错误:Argument of type 'unknown' is not assignable to parameter of type 'string'.
printMessage(value);

就是防止sb瞎写、用之前必须先使用关键字进行类型缩小、这样更加安全一点、any类型

3.1、Ts中的类型 void类型

void通常用来指定一个函数是没有返回值的,那么它的返回值就是void类型

function sum(num1: number, num2: number){
  console.log(num1 + num2)
}

这个函数我们并没有给他写任何类型、那么它默认返回值的类型就是void的、我们也可以显示的来指定返回值是void类型

function sum(num1: number, num2: number): void {
  console.log(num1 + num2)
}

这里还有一个注意事项:

我们可以将undefined赋值给void类型,也就是函数可以返回undefined

function sum(num1: number, num2: number): void {
  console.log(num1 + num2)
  return undefined
}

当基于上下文的类型推导(Contextual Typing)推导出返回类型为 void 的时候,并不会强制函数一定不能返回内容

type FnType=()=>void
const foo:FnType=()=>{
    return 123
}
const names=["abc","cba","nba"]
names.forEach(item=>{
    item.length
})
const names = ["abc", "cba", "nba"]

// 了解即可: 基于上下文类型推导的函数中的返回值如果是void类型, 并且不强制要求不能返回任何的东西
names.forEach((item: string, index: number, arr: string[]) => {
  console.log(item)
  return 123
})

小总结

1、在TS中如果一个函数没有任何的返回值, 那么返回值的类型就是void类型

2、如果返回值是void类型, 那么我们也可以返回undefined(TS编译器允许这样做而已)

3、上述的匿名函数的类型是经过上下文进行类型推导推导出的void类型、并没有写死,你会发现也是可以返回数据的、但是会被忽略掉、并有没有任何意义(了解即可)

3.2、Ts中的类型 never类型

1、never类型的应用场景

1、开发中很少实际去定义never类型,某些情况下会自动进行类型推导出never

2、开发框架(工具)的时候可能会用到never

3、封装一些类型工具的时候可以使用never,(后面会讲一些类型体操的题目:never)

2、什么是never类型

never表示永远不会发生值的类型,比如一个函数

  • 如果一个函数中是一个死循环或者抛出一个异常,那么这个函数会返回东西吗?
  • 不会,那么写void类型或者其他类型作为返回值类型都不合适,我们就可以使用never类型;
//一、实际开发中只有进行类型推导时, 可能会自动推导出来是never类型, 但是很少使用它
//1、一个函数是死循环
funcation loopFun():never{
    while(true){
        console.log("-------")
    }
}
foo()

//2、抛出异常
function loopErr():never{
    throw new Error()
}   //----------最新的版本可能有变化、本来经过类型推导应该推导出来的是never类型、但是现在看却是void类型的

//3.解析歌词工具
function parseLyric(){
    return []    //这个函数的返回值就是  function parseLyric():never[],表示这个里边永远不会放任何东西
}    

注意:实际开发中我们并不会使用这个never类型,只有进行类型推导时可能会推导出来是never类型

// 二、在封装框架/工具库的时候可以使用一下never类型 (之前尤雨溪、知乎上回答了TypeScript里面的never类型到底有什么用,尤大回复了一个跟官方案例差不多的答案)

// handleMessage 这个方法是A工作人员开发的、B开发要用、我传一个 true,发现由于类型限制报错、那么直接在工具类上加一个联合类型|boolean,好了调用不报错了
// 但是如果我们没有处理这个case的、通过const check:never=message 检测出我们并没有处理这种参数的case运算
function handleMessage(message: string | number | boolean) {
  switch (typeof message) {
    case "string":
      console.log(message.length)
      break
    case "number":
      console.log(message)
      break
    case "boolean":
      console.log(Number(message))
      break
    default: //其他时候在扩展工具的时候, 对于一些没有处理的case, 可以直接报错(check就报红线了、加一个case分支处理下就好了)
      const check: never = message
  }
}

handleMessage("aaaa")
handleMessage(1234)

// 另外同事调用这个函数
handleMessage(true)

业务开发、基本很少定义never 类型、但是写框架,工具类可能会用到

3.3、Ts中的类型 tuple类型

发音:tepou

元组类型在某些编程语言里边它是有的比如Python、swift等、所谓元组是多个元素组合在一起的意思。

元组类型和数组类型还是有点相似的、区别在于他可以存放不同的数据类型、并且每个位置的数据类型都是明确的

题目:假如我们现在需要保存我们个人信息 why 18 1.88,我想要用一种数据结构把他保存起来

// 1.使用数组类型
// 不合适: 数组中最好存放相同的数据类型, 获取值之后不能明确的知道对应的数据类型
const info1: any[] = ["why", 18, 1.88]
const value = info1[2]
console.log()

// 2.使用对象类型(最多)
// 我为了保存值、我必须写对应的key,增加了我们的带码量、其实也算不上大的缺点(总不能一行也不写就实现功能)
const info2 = {
  name: "why",
  age: 18,
  height: 1.88
}

// 3.使用元组类型
// 元组数据结构中可以存放不同的数据类型, 取出来的item也是有明确的类型
// 元祖类型、即有类型同时有没有强制增加一些key、通过编译后就没有key了,所以元祖类型相当与是一种介于数组和介于对象之间的一种,综合一点保存多种数据的一种类型,
// 如果你现在有一些数据、并且这些数据、你现在不希望用对象存储,同时你觉得,他的数据类型也不一样,有不想用数组来保存数据、这个时候就可以使用元祖类型
const info3: [string, number, number] = ["why", 18, 1.88]
const value2 = info3[2]

//4.tuple通常可以作为返回的值,在使用的时候会非常的方便; 有泛型的写法暂时用any代替
function useState(initialState: number): [number, (newValue: number) => void] {
  let stateValue = initialState
  function setValue(newValue: number) {
    stateValue = newValue
  }
  //函数中返回的是两个值
  return [stateValue, setValue]
}

const [count, setCount] = useState(10)
console.log(count)
setCount(100)

面试题:元组类型和数组类型有什么区别?

首先,数组中通常建议存放相同类型的元素,不同类型的元素是不推荐放在数组中。(可以放在对象或者元组中)

其次,元组中每个元素都有自己特性的类型,根据索引值获取到的值可以确定对应的类型;

const info:(string|number)[]=["why",18,1.88]
const item1=info[0]  //不确定的类型

const tInfo:[string,number,number]=["why",18,1.88]
const item2=tInfo[0] //一定是string类型

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值