在自学TypeScript的操作过程中,他们能明晰感受到它与JavaScript的差别,当中类别表述增添的细致和规范化,能提升标识符的写作性和可移植性。那对js开发人员最常见的表达式,又该怎样去表述,责任编辑将如是说ts中的表达式类别表述。
一、表达式类别
1. 表达式类别的表述:
在采用TypeScript时,他们建立表达式要明晰三个点:
确认模块的类别
确认codice的类别
透过表达式新闻稿建立表达式:
function fn (num : number) : void {
console.log(num)
}
他们在调用表达式并能获得表达式的类别提示信息,提示信息他们需要什么类别的模块,codice是什么类别:
透过表达式表达式建立表达式:
const fn = function(num : number) : void {
console.log(num)
}
同样,他们先来看下变量fn的类别:
相比前者,表达式表达式的写法可以增加写作体验,例如他们用type关键字,将表达式类别提取出来:
type FnType = (num: number) => void
const fn : FnType = (num) => {
console.log(num);
}
那当他们在采用函数‘fn’时,获得的提示信息应该是类别‘FnType’为主:
将表述好的表达式类别规范化‘fn’变量,他们在赋值时无需再书写表达式模块以及表达式codice的类别,typescript会对赋值内容进行自动推导再将两者对比。
2. 可选模块与默认模块:
可选模块:
他们先看一个案例:
function fn(a, b){
// 如果调用fn时有传入b,则进行b的打印
if(b !== undefined) console.log(b)
console.log(a)
}
在JavaScript中,他们表述好一个表达式的模块是用于哪块逻辑,在调用表达式时,如果模块没传入,默认是传undefined。
但在Ts中,表达式类别的表述,必须对每个模块的类别进行表述,而面对这种非必选的模块,需要透过”?”符号进行标记:
// 表达式新闻稿
function fn(a: number, b?: string) : void {
if (b !== undefined) console.log(b)
console.log(a)
}
// 表达式表达式
type FnType = (a: number, b?: string) => void
const fn: FnType = (a, b) => {
if (b !== undefined) console.log(b)
console.log(a)
}
可选模块必须在必填模块后,否则不符逻辑,会获得对应的错误提示信息:
默认模块:
为什么要将可选模块和默认模块区分开来?主要是在写法上容易混淆,他们先看下表达式表达式的写法:
function fn(a: number, b = 1) : void {
if (b !== undefined) console.log(b)
console.log(a)
}
接着他们可以看下typescript编译器对fn类别的提示信息:
在表达式新闻稿中,模块给予默认值后无需再写类别,默认值的类别为模块类别,且这个模块为可选模块。
接下来是表达式表达式对默认模块的书写,类别的表述书写可选,而表达式的表述书写默认值:
type FnType = (a: number, b?: string) => void
const fn: FnType = (a, b = 1) => {
if (b !== undefined) console.log(b)
console.log(a)
}
这里不难理解,他们对fn进行类别表述,要求的是第二个模块为可选。
赋值给fn的匿名表达式,在进行类别推导时,认定第二个携带默认值的模块为可选模块,符合fn变量类别的要求。
他们复习一下js中的argument,他们可以透过a
function fn(a, b){
console.log(arguments);
}
fn(1,2,3,4) // arguments : {0:1,1:2,2:3,3:4}
在ts中,他们表述表达式接收多少个模块后,无法传入更多的模块:
他们可以回忆一下,在ES6中对多余模块的收集:
function fn(a, b, …rest){
console.log(rest) // [ 3, 4 ]
}
fn(1,2,3,4)
同理,在ts中,他们需要对剩余模块进行类别表述,确认剩余模块的类别。
4. 关于this的类别表述:
在js中,this的指向是一个重要知识点,在ES6之前,普通表达式的this指向只能在调用时确认,当中包括this的指向丢失,call、apply、bind对this指向的改变等;在ES6自学箭头表达式后,this的指向可以在表达式表述时确认,箭头表达式的this指向表达式所在的执行上下文。
那在细致的逻辑中,一个表达式的表述应该明晰。
表达式的模块(需要什么模块,模块的数据类别)。
表达式的作用(返回什么类别的数据,或者是没有codice)。
表达式服务的目标(this的指向)。
他们先看一个情景前提:
const example = {
num: 1,
getNum() {
console.log(this.num);
}
}
const fn = example.getNum
fn() //undefined, this => window
这是最常见的一种场景,getNum表达式表述的目的是打印example中的num属性,在赋值操作过程中,this隐式丢失,导致表达式调用时指向window。
没错,可能有同学认为,表达式的功能既然能打印example的num属性,也可以打印window的num属性,那取出来也没什么问题,甚至他们可以透过call来指向他们想取出num属性的目标:
example.getNum.call(otherTarget) // otherTarget.num
但如果我这个表达式,取出的num属性有类别要求,用于后续逻辑,其他目标的num属性类别是否符合我后续逻辑的要求?
const example = {
num: {a : 1},
getNum() {
console.log(this.num.a.b);
}
}
// 错误采用
const otherTarget = {
num : 111
}
example.getNum.call(otherTarget) // error
所以他们必须明晰表达式服务的目标,以免误用导致逻辑错误。
那在ts中,如果明晰了表达式服务的目标,也就是getNum表达式服务于example对象,他们可以对this进行类别表述:
interface Example {
num : number,
getNum : (this : Example) => void
}
const example : Example = {
num: 1,
getNum() {
console.log(this.num);
}
}
表述好表达式服务的目标后,他们可以再对比同一段逻辑的采用操作过程:
5. 表达式重载(Overloads):
在js中表述一个表达式,他们可以透过判断用户传入的类别来决定执行哪一点逻辑:
function fn (target) {
if(typeof target === string) return 1
else return 1
}
fn(1) //return 1
console.log(fn(1)) // return 1
在ts中,他们需要进行参数的类别表述,还需要确认codice的表述:
function fn (target: number | string): string | number {
if(typeof target === string) return 1
else return 1
}
但是这种写法获得的codice会是什么提示信息呢:
如图所示,他们新闻稿的变量f在接受codice后的获得的类别提示信息却是字符串和数值的联合类别,不符合他们设计的目的。
函数重载则符合他们设计表达式的书写要求:
function fn (target:number) : number
function fn (target:string) : string
function fn (target: number | string): string | number {
if(typeof target === string) return 1
else return 1
}
重载用于记录不同的组合列表,他们在调用表达式时,会去进行列表的匹配,由此确认调用者是采用表达式的哪一段逻辑,返回什么类别的数据。
总结
在文章中他们自学表达式的类别表述,在建立表达式时需要确认表达式的模块类别和codice类别,新闻稿表达式和表达式表达式怎样表述,可选模块和默认模块的表述,剩余模块的表述,this的类别表述以及表达式重载。相比js中表达式的书写,ts的自学成本相对较高,但是从js过渡到ts的操作过程又是流畅的。