TypeScript 定义函数的四种方式
第一种方式可以直接调用,后三种需要先实现定义的函数再调用。
第一种 函数声明式:
function sum (x: number, y: number): number {
return x + y
}
// 调用时形参和实参一一对应
sum(1, 2)
第二种 函数表达式:
let sum: (x: number, y: number) => number = (a, b) => a + b
// 或
let sumX = (a: number, b: number): number => a + b
sum(2, 2)
sumX(1, 4)
第三种 接口实现:
interface ISum {
(x: number, y: number): number;
}
// 跟变量声明是等价的:let ISum: (a: number, b: number) => number
let sum: ISum = (a,b) => a + b
sum(4, 2)
第四种 类型别名:(推荐方式)
type ISum = (x: number, y: number) => number
// 应用如下:
let sum: ISum = (a, b) => a + b
sum(3, 2)
函数类型
函数类型包含两部分:参数类型和返回值类型。
- 参数名不一定要相同,只要参数类型匹配,那么就认为它是有效的函数类型。
const sum: (num1: number, num2: number) => number =
function (x: number, y: number): number { return x + y }
- 返回值类型是函数类型的必要部分,如果函数没有返回任何值,必须指定返回值类型为 void 而不能留空。
const sum: (num1: number, num2: number) => void =
function (x: number, y: number): number { console.log(x + y) }
类型推断
如果在赋值语句的一边指定了类型但另一边没有类型的话,TypeScript编译器会自动识别出类型, 这叫做“按上下文归类”,是类型推论的一种。
const getSum: (x: number, y: number) => number = (x, y) => x + y
可选参数
JavaScript里,每个参数都是可选的。没传参的时候,值就是undefined。但在TypeScript中函数参数默认都是必传的,必传的意思并不是不能传递null和undefined作为实参,而是编译器会检查是否为每个参数传入了值。简而言之,编译器会检查传入实参的个数是否和形参相同。
function bar(name: string, age: number): string {
return `${name} age is ${age}`
}
bar('jack', 12) // ok
bar('nike') // Expected 2 arguments, but got 1.
bar('rose', 12, 'shanghai') // Expected 2 arguments, but got 3.
TypeScript的可选参数需要在参数名后使用 ?
标识符 实现可选参数的功能。 比如上例希望 age 是可选的:
function bar(name: string, age?: number): string {
if (age) return `${name} age is ${age}`
return `the name is ${name}`
}
bar('jack', 12) // ok
bar('nike') // ok
bar('rose', 12, 'shanghai') // Expected 1-2 arguments, but got 3.
注意: 可选参数必须跟在必须参数后面。
参数默认值
可以通过为参数提供一个默认值,当参数是可选的且没有传值或传递的值是undefined时,则会使用参数的默认值。
function fullName(firstName: string, lastName: string = 'Smith') {
return `${firstName} ${lastName}`
}
fullName('Bob') // Bob Smith
fullName('Bob', undefined) // Bob Smith
fullName('Bob', 'Adams', 'Sr.') // Expected 1-2 arguments, but got 3.
fullName("Bob", "Adams") // Bob Adams
参数默认值与可选参数不同之处:
- 没有传值时默认参数是取默认值,而可选参数的值是undefined;
- 带默认值的参数不需要放在必选参数的后面。如果带默认值的参数出现在必选参数前面,则调用时必须明确的传入
undefined
值来取得默认值。
剩余参数
TypeScript的剩余参数和ES6的剩余参数一样。
function sum(num1: number, ...rest: number[]): number {
interface ITotal {
(pre: number, cur: number): number;
}
const handle: ITotal = (pre, cur) => pre + cur
return rest.reduce(handle, num1)
}
sum(1, 2, 3, 4, 5, 6, 7) // 28
this
this与箭头函数
TypeScript在 noImplicitThis
模式下,不允许this上下文隐式定义。
const person = {
name: 'Mike',
getName() {
return function() {
console.log(this.name)
}
}
}
const getName = person.getName()
getName()
上例函数中的this在 noImplicitThis
模式开启时报错(this' implicitly has type 'any' because it does not have a type annotation),未开启时指向window。
可以将返回函数设置成箭头函数解决该问题。
const person = {
name: 'Mike',
getName() {
return () => {
console.log(this.name)
}
}
}
const getName = person.getName()
getName() // 'MIke'
但上面的代码还是会存在一些问题。因为即使能够保证箭头函数里面的 this 与外层函数的this保持一致, 但是外层函数的this不一定就是 dog 这个对象。函数中的this依旧是any类型。
this参数
可以通过给函数添加隐式的 this 参数类型声明。this参数是个假的参数,它出现在参数列表的最前面。
interface IPerson {
name: string;
getName(this: IPerson, firstName: string): () => void;
}
const person: IPerson = {
name: 'Mike',
getName: function(this: IPerson, firstName: string) {
return () => {
console.log( `${this.name} ${firstName}` )
}
}
}
const getNameX = person.getName('Mr.')
getNameX() // Mike Mr.
回调参数里的this
这一部分还没彻底搞清楚,国内几乎找不到深入讲解TypeScript的教程。后续补充。
重载
函数重载允许一个函数通过不同数量或类型的参数,返回不同类型的值。
比如:实现一个函数 reverse,输入数字的时候,输出反转的数字,输入字符串的时候,输出反转的字符串。
通过联合类型实现:
function reverse(val: number | string): number | string {
if (typeof val === 'number') {
return Number(val.toString().split('').reverse().join(''))
} else if (typeof val === 'string') {
return val.split('').reverse().join('')
}
}
联合类型的缺陷就是不能精确表达不同输入类型对应的输出类型。这时可以通过函数重载定义多个函数类型。
函数重载实现:
function reverse(num: number): number;
function reverse(str: string): string;
function reverse(val: any): any {
if (typeof val === 'number') {
return Number(val.toString().split('').reverse().join(''))
} else if (typeof val === 'string') {
return val.split('').reverse().join('')
}
return false
}
console.log(reverse(123456)) // 654321
console.log(reverse('sina')) // 'anis'
以上前两个函数是函数重载列表,第三个是函数实体。
注意:重载只能通过 function
声明。
网友评论