目录
- 参数类型
- 基本声明
- 默认参数
- 剩余参数
- 可选只读
- 匿名函数
- 回调函数
- 返回值类型
- 函数类型
- 表达式
- 调用签名
- 构造签名
- 函数的重载
- this
- 可推导的
- 编译选项
- this类型
- 内置工具
函数是JavaScript
非常重要的组成部分,TypeScript
中也是如此,TypeScript
提供了强大的类型系统来帮助我们定义函数的参数、返回值以及函数本身的类型
参数类型
基本声明
参数的类型注解:声明函数时,可以在每个参数后添加类型注解,以声明函数接受的参数类型
function add(num1: number, num2: number) {
console.log(num1,num2)
}
add(10, 20)
add('10', '20') // Argument of type 'string' is not assignable to parameter of type 'number'
默认参数
如果调用时没有传递该参数,则使用默认值,这个时候greeting
的类型其实是 undefined
和 string
类型的联合
function greet(name: string, greeting: string = "Hello") {
return `${greeting}, ${name}!`;
}
console.log(greet("Alice")); // Hello, Alice!
console.log(greet("Alice", "Good day")); // Good day, Alice!
剩余参数
使用剩余参数可以让函数接收任意数量的参数,剩余参数会被收集到一个数组中
function sum(...numbers: number[]) {
return numbers.reduce((acc, num) => acc + num, 0);
}
console.log(sum(1, 2, 3, 4)); // 10
可选只读
-
可以指定某个参数是可选的,可选类型需要在必传参数的后面,这个参数
z
依然是有类型的,类型是:number | undefined
function fo1(x: number, y: number, z?: number) { console.log(x, y, z) // 10 20 undefined } fo1(10, 20)
-
readonly
关键字主要用于对象和数组等复合类型的参数,而对于普通的基本类型(如number
,string
等),它们是按值传递的,没必要使用readonly
function foo2(data: { name: string, readonly age?: number }) { console.log(data) }
匿名函数
匿名函数与函数参数声明会有一些不同:
-
当一个函数出现在
TypeScript
可以确定该函数会被如何调用的地方时,该函数的参数会自动指定类型 -
这个过程称之为上下文类型(
contextual typing
),因为函数执行的上下文可以帮助确定参数和返回值的类型
const names: string[] = ['abc','cba','eee','ghj']
names.forEach((n => { // 这个n就是string类型,不需要在指定类型
console.log(n.toLocaleUpperCase())
}))
回调函数
函数可以作为函数的参数回调,TypeScript
对于传入的函数类型的多余的参数会被忽略掉
function executeCallback(callback: (message: string) => void) {
callback("This is a callback message");
}
executeCallback((msg: string) => {
console.log(msg); // 输出: This is a callback message
});
返回值类型
-
可以添加返回值的类型注解,这个注解出现在函数列表的后面,返回的类型不对会报错
-
和变量的类型注解一样,通常情况下不需要返回类型注解,因为
TypeScript
会根据return
返回值推断函数的返回类型
函数类型
表达式
-
可以编写函数类型的表达式(
Function Type Expressions
),来表示函数类型(参数列表) => 返回值类型
-
在某些语言中,可能参数名称
num1
和num2
是可以省略,但是TypeScript
是不可以的 -
(x: number, y: number) => number
是函数的类型签名,它表示该函数接受两个number
类型的参数并返回一个number
type mulType = (num1: number, num2: number) => number
const mul: mulType = function (num1: number, num2: number){
return num1 * num2
}
mul(10,20)
调用签名
函数的调用签名(Call Signatures
是从对象的角度来看待这个函数, 函数也可以有其他属性)
/* 作为函数类型 */
interface ICacl {
key: string;
(num1: number, num2: number): void;
}
const cacl: ICacl = function(num1: number, num2: number): void {
console.log(num1, num2);
};
// 给函数对象赋予属性 key,不赋值会报错
cacl.key = "someKey";
console.log(cacl.key); // 输出: "someKey"
cacl(10, 20); // 输出: 10 20
/* 作为参数 */
interface ISign {
key: string,
(num1: number, num2: number): void
}
function sum(num: number, callBack: ISign) {
console.log(callBack.key)
callBack(num, 20)
}
const fn: ISign = (num1: number, num2: number) => { }
fn.key = 'params'
sum(10, fn)
构造签名
构造签名(constructor signature
)是用于定义类的构造函数类型的语法,定义一个对象或类可以被实例化,描述了使用 new
关键字实例时所需的参数和返回的实例类型
interface IPerson {
new (name: string, age: number): Person
}
class Person {
name: string
age: number
constructor(name: string, age: number) {
this.name = name
this.age = age
}
}
let obj:IPerson = Person
console.log(new obj('obj', 18))
函数的重载
-
在
TypeScript
中,可以去编写不同的重载签名(overload signatures
)来表示函数可以以不同的方式进行调用 -
一般是编写两个或者以上的重载签名,再去编写一个通用的函数以及实现
-
调用时它会根据传入的参数类型来决定执行函数体时,到底执行哪一个函数的重载签名
/*
在TypeScript中,如果编写一个add函数,希望可以对字符串和数字类型进行相加,应该如何编写呢?
*/
function add1(a1: string | number, a2: string | number, a3: string | number) {
return a1 + a2 + a3 // 报错:运算符“+”不能应用于类型“string | number”和“string | number”
}
// 编写不同的重载签名
function add(a1: number, a2: number, a3: number): number
function add(a1: string, a2: string): string
function add(a1: any, a2: any, a3?: any): any {
return a1 + a2 + a3
}
console.log(add(10, 20, 30)); // 60
console.log(add("aaa", "bbb")); // aaabbbundefined
this
this
是JavaScript
中一个比较难以理解和把握的知识点,目前的Vue3
和React
开发中你不一定会使用到this
, Vue3
的Composition API
中和React
的Hooks
开发中很少见到this,但是还是要简单掌握一些TypeScript
中的this
可推导的
默认情况下TypeScript
在编译时,this
是可以正确去使用的,因为在没有指定this
的情况,this
默认情况下是any
类型的
const bar = {
name: 'bar',
foo: function (){
console.log(this.name)
}
}
bar.foo()
function foo(){
console.log(this)
}
编译选项
-
当使用命令
tsc --init
生成tsconfig.json
的配置文件时,有的this
就会报错 -
主要由
tsconfig.js
中的noImplicitThis
值控制 -
在设置了
noImplicitThis
为true
时,TypeScript
会根据上下文推导this
,但是在不能正确推导时就会报错,需要明确的指定this
const bar = {
name: 'bar',
foo: function (){
console.log(this.name) // 可以类型推导出this: { name: string; foo: () => void; }
}
}
bar.foo()
function foo(){
console.log(this) // 这时推导不出this的具体类型,修改tsconfig.json中的 noImplicitThis值为 false 就不会报错
}
foo()
this类型
在开启noImplicitThis
的情况下,必须指定this
的类型:
-
函数的第一个参数可以根据该函数之后被调用的情况,用于声明
this
的类型(名词必须叫this
) -
在后续调用函数传入参数时,从第二个参数开始传递的,
this
参数会在编译后被抹除
const bar = {
name: 'bar',
foo: function (){
console.log(this.name) // 可以类型推导出this: { name: string; foo: () => void; }
}
}
bar.foo()
function foo(this: {name: string, age: number}, num: number){
console.log(this, num) // 打印:name: 'foo', age: 18} 20 这时this的具体类型就是 {name: string, age: number}
}
foo.call({name: 'foo', age: 18}, 20)
内置工具
Typescript
提供了一些this
相关的工具来辅助进行常见的类型转换,这些类型全局可用:
-
ThisParameterType<Type>
:用于从函数类型中提取this
参数的类型,如果函数没有明确指定this
参数,那么ThisParameterType
会解析为unknown
function foo1(this: {name: string, age: number}, num: number){ console.log(this, num) // 打印:name: 'foo', age: 18} 20 这时this的具体类型就是 {name: string, age: number} } foo1.call({name: 'foo', age: 18}, 20) type thisType1 = ThisParameterType<typeof foo1> // type thisType = { name: string; age: number;} function foo2(num: number){ console.log(num) } foo2(20) type thisType2 = ThisParameterType<typeof foo2> // type thisType2 = unknown
-
OmitThisParameter<Type>
:从函数类型Type
中 移除this
参数。如果Type
没有this
参数,或者Type
不是一个函数类型,那么OmitThisParameter<Type>
返回Type
本身function foo1(this: {name: string, age: number}, num: number){ console.log(this, num) // 打印:name: 'foo', age: 18} 20 这时this的具体类型就是 {name: string, age: number} } foo1.call({name: 'foo', age: 18}, 20) type fnType1 = OmitThisParameter<typeof foo1> // type fnType1 = (num: number) => void function foo2(num: number){ console.log(num) } foo2(20) type fnType2 = OmitThisParameter<typeof foo2> // type fnType2 = (num: number) => void type fnType3 = OmitThisParameter<string> // type fnType3 = string
-
ThisType<T>
:这个类型不返回一个转换过的类型,它被用作标记一个上下文的this
类型-
ThisType
只能用于对象字面量,它不能在类或函数中直接使用 -
ThisType<T>
本身并不会在对象里定义this
,它只是告诉TypeScript
如何推断this
的类型 -
需要与
TypeScript
的noImplicitThis
和noImplicitAny
编译选项一起使用,确保this
是明确的
interface IState { name: string age: number } interface IData { state: IState running: () => void } const info1: IData = { state: { name: 'info1', age: 18, }, running() { console.log(this) // 这时的this类型推断为是IData,但它应该是IState 打印:{name: 'info1', age: 18} } } info1.running.call(info1.state) const info2: IData & ThisType<IState> = { state: { name: 'info2', age: 18, }, running() { console.log(this) // 这时的this类型是对的是IState,打印:{name: 'info2', age: 18} } } // 需要手动绑定 this 到 state,因为ThisType<IState> 仅仅是一个上下文类型提示工具,而不会直接影响运行时的 this 绑定 info2.running.call(info2.state)
-