# 引用类型

在TS中提供了一些引用类型,例如:Array(数组)、String(字符串)、Date(日期对象)、RegExp(正则表达式)等。

# 初始化数组的两种方法

# 声明数组的方法

声明数组跟声明一个普通变量是一样的,都是通过 var let 关键字实现的,只不过数组的类型说明符比较复杂而已。

let arr1:number[ ]     //声明一个数值类型的数组
let arr2:Array<string>  //声明一个字符串类型的数组

数组是存储大量数据的集合,声明数组之后,需要给数组存储数据。这时候有两种方法:

  • 字面量赋值法:直接使用[ ]对数组进行赋值。
  • 构造函数赋值法: 字面量赋值法
//定义一个空数组,数组容量为0
let arr1:number[] = [] 
//定义一个数组时,直接给数组赋值
let arr2:number[] = [1,2,3,4,5]
//定义数组 的同时给数组赋值
let arr3:Array<string> = ['jspang','技术胖','xxx']//使用了内置的泛型Array
let arr4:Array<boolean> = [ true,false,false]

# ts数组和元组的处理

  • 数组 :在元素类型后面加上[]或者使用内置泛型
let arr: number[] = [1, 2];
let arr1: Array<number> = [1, 2];
  • 多维数组
var arr_name:number[][][]=[ [[1]],[[2,3,4]] ]
console.log(arr_name)
  • TypeScript 可以通过 ReadonlyArray<T> 设置数组为只读,那么它的所有写方法都会失效。
let arr: ReadonlyArray<number> = [1,2,3,4,5];
arr[0] = 6; // Index signature in type 'readonly number[]' only permits reading
  • “readonly”类型修饰符仅允许用于数组和元组文字类型。
let arr:readonly number[] = [1,2,3,4,5];
console.log(arr)
//let arr1:readonly Array<number> = [1,2,3,4,5];
//'readonly' type modifier is only permitted on array and tuple literal types.
//console.log(arr1)

  • 元组
  1. 元组类型用来表示 已知元素数量和类型的数组 ,各元素的类型不必相同,对应位置的类型需要相同。
const list: [string, number] = ['Sherlock', 1887]   // ok
  1. 元组要注意元组的越界问题,虽然可以越界添加元素(不建议),但是 不可越界访问
const list: [string, number] = ['Sherlock', 1887]
list.push('hello world')

console.log(list)      // ok [ 'Sherlock', 1887, 'hello world' ]

// 测试是可以通过forEach等不需要下标操作的方法获取值
list.forEach((el,i)=>{
  console.log(el)
})
// Sherlock
// 1887
// hello world

// console.log(list[2])   // Tuple type '[string, number]' of length '2' has no element at index '2'

  1. 元组类型允许在元素类型后缀一个 ? 来说明元素是可选的
let list: [number, string?, boolean?]
list = [10, 'Sherlock', true]
list = [10, 'Sherlock']
console.log(list)
// list = [10]
  1. 元组类型的 Rest 使用,元组可以作为参数传递给函数,函数的 Rest 形参可以定义为元组类型
declare function rest(...args: [number, string, boolean]): void
<===>等价
declare function rest(arg1: number, arg2: string, arg3: boolean): void
const list: [number, ...string[]] = [10, 'a', 'b', 'c']
list.push(122)
console.log(list[4])//122
/**
* TS 数组和 JS 数组是一样的
* 变量提示,const numberArr: number[]
*/
const numberArr = [1, 2, 3];

const arr: number[] = [1,2,3];
const stringArr: string[] = ['a', 'b', 'c'];
// 如果这个数组里面既存数字又存字符串,如何写
const arr1: (number | string)[] = [1, '2' ,3];


// 除了基本类型的数组,对象类型的数组怎么写
const objectArr: {name: string, age: number}[] = [{name:'a', age:16}]
// 将上面的写法简化下,利用 type alias 类型别名
type User = {name: string, age: number}
const objectArr1: User[] = [{name:'a', age:16}]


// 元组 tuple
const teacherinfo = ['zina', 'girl', 18];
/**
* 鼠标悬浮变量
* const teacherinfo: (string | number)[],
* 推断出 teacherinfo 里面存储的值可能是 string, 也可能是 number
*/
const teacherinfo1: (string | number)[] = ['zina', 'girl', 18];
/**
* 如果说后面的这个数组,长度肯定只有三个,
* 第一个肯定是字符串,第二个肯定是字符串,第三个肯定是数字
* 这个时候第一个改成数字不会报错,数组这种类型约束已经约束不到了
* 这个时候元组的作用就显现了
*/
const teacherinfo2: [string, string, number] = ['zina', 'girl', 18];
/**
* 这种就是元组的写法,这个时候后面加一个,或者改动三者的类型都会报错
* 一个数组里面的长度和类型都是固定的时候,就可以使用元组
* 场景:读取 excel csv 的时候
*/
const teacherinfo3: [string, string, number][] = [
['zina', 'girl', 18],
['zina', 'girl', 18],
['zina', 'girl', 18]
];

# 数组的弊端和元组的应用场景

// hook: useState
// const [counter, setCounter] = {counter: , setCounter:}

function useState<T>(state: T) {
  let currentState = state
  const changeState = (newState: T) => {
    currentState = newState
  }
  const info: [string, number] = ["abc", 18]
  const tuple: [T, (newState: T) => void] = [currentState, changeState]
  return tuple
}
//可以清晰的判断数据的格式,而不是只能使用any
const [counter, setCounter] = useState(10);
setCounter(1000)
const [title, setTitle] = useState("abc")
const [flag, setFlag] = useState(true)

# ts日期对象 正则

let d1:Date = new Date('2018/09/06 05:30:00')
let d2:Date = new Date('2018-09-06 05:30:00')
let d3:Date = new Date('2018-09-06T05:30:00')
console.log(d1)
console.log(d2)
console.log(d3)

let reg1:RegExp = new RegExp("jspang")  //表示字符串规则里含有jspang
console.log(reg1)
let reg2:RegExp = new RegExp("jspang",'gi')
console.log(reg2)
let reg3:RegExp = /jspang/
let reg4:RegExp = /jspang/gi

# ts Promise中类型的使用

  • 在 Promise 的情况下,泛型允许指定 Promise 将解决为什么类型的值。
new Promise<string>((resolve) => {
  resolve('abc')
}).then((res) => {
  console.log(res.length)
})

# TS函数

函数类型:

(num1: number, num2: number) => void//代表的就是一个函数类型

参数类型注解:当声明一个函数的时候,可以在每个参数后面添加一个类型注解,声明函数可以接受什么类型的参数。当参数有了类型注解的时候,TypeScript 便会检查函数的实参

// Parameter type annotation
function greet(name: string) {
  console.log("Hello, " + name.toUpperCase() + "!!");
}
greet(100)// 类型“number”的参数不能赋给类型“string”的参数。

返回值类型注解:也可以添加返回值的类型注解,跟变量类型注解一样,也不需要总是添加返回值类型注解,TS会基于它的 return 语句推断函数的返回类型。

  • 基本格式
function add(x: number, y: number): number {
    return x + y;
}

上面的代码只是对 = 等号右侧的匿名函数进行了类型定义,等号左侧的 add 同样可以添加类型:

const add: (x: number, y: number) => string = function(x: number, y: number): string {
  return (x + y).toString()
}

可以看到,等号左侧的类型定义由两部分组成:参数类型和返回值类型,通过 => 符号来连接。

//也可以省略左边
const add = (x: number, y: number): string => (x + y).toString()

也可以将约束条件提取出来:

let compute: (x:number,y:number) =>number
compute = (a,b) => {
  console.log(a+b)
  return a+b
}
compute(1,3)

函数类型表达式:最简单描述一个函数的方式是使用 函数类型表达式(function type expression)。 它的写法有点类似于箭头函数:

function greeter(fn: (a: string) => void) {
  fn("Hello, World");
}
 
function printToConsole(s: string) {
  console.log(s);
}
 
greeter(printToConsole);

也可以使用类型别名(type alias)定义一个函数类型

type GreetFunction = (a: string) => void;
function greeter(fn: GreetFunction) {
  // ...
}

# ts函数中的this

// this是可以被推导出来 info对象(TypeScript推导出来)
const info = {
  name: "why",
  eating() {
    console.log(this.name + " eating")
  }
}
info.eating()
export {}

上面的代码是可以正常运行的,也就是TypeScript在编译时,认为this是可以正确去使用的:TypeScript认为函数 sayHello 有一个对应的this的外部对象 info,所以在使用时,就会把this当做该对象。

// "this" 隐式具有类型 "any",因为它没有类型注释。
// 此容器隐藏了 "this" 的外部值。
function eating() {
  console.log(this.name);
}

const info = {
  name: "why",
  eating: eating,
};

// 隐式绑定
info.eating();

这段代码运行会报错的:

  • TypeScript进行类型检测的目的是让代码更加的安全;
  • 所以这里对于 eating 的调用来说,虽然将其放到了info中,通过info去调用,this依然是指向info对象的;
  • 但是对于TypeScript编译器来说,这个代码是非常不安全的,因为也有可能直接调用函数,或者通过别的对象来调用函数;

这个时候,通常TypeScript会要求明确的指定this的类型:

type ThisType = { name: string };
//这里的this如果要传,必须是第一个位置,且他是作为类型注解而不是参数
function eating(this: ThisType, message: string) {
  // 如果没有this注解,那么这里的this指向any
  console.log(this.name + " eating", message);
}

const info = {
  name: "why",
  eating: eating,
};

// 隐式绑定
info.eating("哈哈哈");

// 显示绑定
eating.call({name: "kobe"}, "呵呵呵")
eating.apply({name: "james"}, ["嘿嘿嘿"])

# 匿名函数的参数

匿名函数与函数声明会有一些不同:

  • 当一个函数出现在TypeScript可以确定该函数会被如何调用的地方时;
  • 该函数的参数会自动指定类型;
const names = ["abc", "cba", "nba"]
// item根据上下文的环境推导出来的, 这个时候可以不添加的类型注解
// 上下文中的函数: 可以不添加类型注解
names.forEach(function(item) {
  console.log(item.split(""))
})

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

# 调用签名

在 JavaScript 中,函数除了可以被调用,自己也是可以有属性值的。函数类型表达式并不能直接支持声明属性,如果想描述一个带有属性的函数,可以在一个对象类型中写一个调用签名(call signature)。

  • 回调签名
//给函数添加属性,要通过对象的方式来定义
type DescribableFunction ={
  //在对象里定义一个属性名字discription,并给它定义一个string类型
  description:string
  //再定义一个函数体 (函数参数:类型):返回值的类型
  //注意:在参数列表和返回类型之间使用:而不是=>
  (someArg:number):boolean
} 

//定义一个doSomething函数调用函数参数,业务代码处理部分
export function doSomething(fn:DescribableFunction){
  //调用函数属性和函数本身(函数要传递一个number类型,这里传入一个6)
  console.log(fn.description + 'return' + fn(6));
}

//doSomething需要传入一个参数fn,这里定义一个fn1将参数传给doSomething()
function fn1(n:number){
  console.log(n);
  //这里要返回一个boolean类型
  return true
}

//那么fn1就可以绑定属性传参了,注意这里绑定的属性必须是type DescribableFunction{}对象里定义过的属性
fn1.description='hello'
//doSomething就可以将一个function传入了,fn1满足了返回的类型
doSomething(fn1)

注意这个语法跟函数类型表达式稍有不同,在参数列表和返回的类型之间用的是 : 而不是 =>

  • 构造签名
export class Ctor {
  //类里顶一个参数s类型sting
  s: string
  //再定义一个构造函数,这个函数需要传入一个s参数string类型,然后把参数s赋值给this.s
  constructor(s: string) {
      this.s = s
  }
}


//1.通过type来定义一个构造签名,取名为SomeConstructor,后面是对象
type SomeConstructor = {

  //在对象里先定义一个调用签名 格式:(函数的参数:参数的类型):返回的类型/构造的类
  new (s: string): Ctor //这是一个够咱函数的签名
  // new 关键字表示这是一个构造函数
  // (s: string) 构造函数的 参数列表,表示这个构造函数 接受一个类型为string的参数s
  // :Ctor是构造函数的返回类型
}
//3.使用函数 参数为Ctor:类型为type定义好的类型名:SomeConstructor
function Fn(Ctor: SomeConstructor) {
  //Ctor: SomeConstructor可以理解为一个构造函数,那么这里就可以调用这个函数了,Ctor('字符串'),
  //但是这里只实现了调用签名,并没有实现构造签名,在ts里要实现构造签名,需要在type SomeConstructor={}对象里的方法添加一个new,
  //这样它就是一个构造函数类型了,那么在这里的Ctor('字符串')前面也要加一个new才能够被实例化。如果要返回这个实例,
  //前面再加一个return,那么这里就返回了一个构造函数的实例了
 return new Ctor('字符串');
}

//4.调用函数,传入的参数是构造函数类型,这里传入Ctor
const fn = Fn(Ctor)
//5.打印,运行 node 05-constructor.js
console.log(fn.s);

有的对象,比如JavaScript的Date对象,可以在有 new或者没有new的情况下,都可以被调用,那我们可以在同一个类型中,任意地结合调用和构造签名

//1.定义一个接口,名字CallOrConstructor,可以调用也可以构造的意思
interface CallOrConstructor {

  //(2)再构造一个函数,返回一个Date类型。这叫构造签名的方式
  new(s: string): Date
  //(1)定义一个函数体,传参为可选型。这叫调用签名的方式
  (n?: number): number
}

//2.使用接口类型
export function Fn(date: CallOrConstructor) {
  //使用构造签名函数,new实例化date再传入字符串参数
   let d = new date('2000-10-2')
  //使用调用签名
  let n = date(100)
}

//以上,实现了结合使用调用签名和构造签名 两种方法 去定义了一个类型

# 泛型函数

通过给函数添加一个类型参数 Type,并且在两个地方使用它,我们就在函数的输入(即数组)和函数的输出(即返回值)之间创建了一个关联。现在当我们调用它,一个更具体的类型就会被判断出来

function firstElement<Type>(arr: Type[]): Type | undefined {
  return arr[0];
}
// s is of type 'string'
const s = firstElement(["a", "b", "c"]);
// n is of type 'number'
const n = firstElement([1, 2, 3]);
// u is of type undefined
const u = firstElement([]);

推论:这里没有明确指定 Type 的类型,类型是被 TypeScript 自动推断出来的

function map<Input, Output>(arr: Input[], func: (arg: Input) => Output): Output[] {
  return arr.map(func);
}
// Parameter 'n' is of type 'string'
// 'parsed' is of type 'number[]'
const parsed = map(["1", "2", "3"], (n) => parseInt(n));
console.log(parsed)

# 函数约束 extends

有的时候,想关联两个值,但只能操作值的一些固定字段,这种情况,可以使用 约束(constraint) 对类型参数进行限制。

写一个函数,函数返回两个值中更长的那个。为此,我们需要保证传入的值有一个 number 类型的 length 属性。使用 extends 语法来约束函数参数:

function longest<Type extends { length: number }>(a: Type, b: Type) {
  if (a.length >= b.length) {
    return a;
  } else {
    return b;
  }
}
 
// longerArray is of type 'number[]'
const longerArray = longest([1, 2], [1, 2, 3]);
// longerString is of type 'alice' | 'bob'
const longerString = longest("alice", "bob");
// Error! Numbers don't have a 'length' property
const notOK = longest(10, 100);
// 类型“number”的参数不能赋给类型“{ length: number; }”的参数。

基于传入的参数,longerArray和 longerString 中的类型都被推断出来了。记住,所谓泛型就是用一个相同类型来关联两个或者更多的值。

function minimumLength<Type extends { length: number }>(
  obj: Type,
  minimum: number
): Type {
  if (obj.length >= minimum) {
    return obj;
  } else {
    // obj不一定仅仅只有length属性
    return { length: minimum };
    // Type '{ length: number; }' is not assignable to type 'Type'.
    // '{ length: number; }' is assignable to the constraint of type 'Type', but 'Type' could be instantiated with a different subtype of constraint '{ length: number; }'.
  }
}

这个函数看起来像是没有问题,Type 被 { length: number} 约束,函数返回 Type 或者一个符合约束的值。

而这其中的问题就在于函数理应返回与传入参数相同类型的对象,而不仅仅是符合约束的对象。我们可以写出这样一段反例:

// 'arr' gets value { length: 6 }
const arr = minimumLength([1, 2, 3], 6);
// and crashes here because arrays have
// a 'slice' method, but not the returned object!
console.log(arr.slice(0));
  • 如果不需要约束的其实可以不约束
function firstElement1<Type>(arr: Type[]) {
  return arr[0];
}
 
function firstElement2<Type extends any[]>(arr: Type) {
  return arr[0];
}
 
// a: number (good)
const a = firstElement1([1, 2, 3]);
// b: any (bad)
const b = firstElement2([1, 2, 3]);

# 可选参数和默认参数

function buildName(firstName: string, lastName?: string) {
    if (lastName)
        return firstName + " " + lastName;
    else
        return firstName;
}
 
let result1 = buildName("Bob");  // 正确
let result2 = buildName("Bob", "Adams", "Sr.");  // 错误,参数太多了
let result3 = buildName("Bob", "Adams");  // 正确
// 默认参数:这样第二个参数可传可不传
function calculate_discount(price:number,rate:number = 0.50) { 
    var discount = price * rate; 
    console.log("计算结果: ",discount); 
} 
  • 剩余参数:函数的最后一个命名参数 restOfName 以 ... 为前缀,它将成为一个由剩余参数组成的数组,索引值从0(包括)到 restOfName.length(不包括)。
function buildName(firstName: string, ...restOfName: string[]) {
  return firstName + " " + restOfName.join(" ");
}

let employeeName = buildName("Joseph", "Samuel", "Lucas", "MacKinzie");

# 重载函数

编译器并不知道入参是什么类型的,返回值类型也不能确定。这时可以为同一个函数提供多个函数类型定义来进行函数重载。

function reverse(x: string): string
function reverse(x: number): number

function reverse(target: string | number) {
  if (typeof target === 'string') {
    return target.split('').reverse().join('')
  }
  if (typeof target === 'number') {
    return +[...target.toString()].reverse().join('')
  }
}
console.log(reverse('imooc'))   // coomi
console.log(reverse(23874800))  // 847832

在这个例子中,写了两个函数重载,一个接受一个参数,另外一个接受三个参数。前面两个函数签名被称为重载签名 (overload signatures)。

然后,写了一个兼容签名的函数实现,称之为实现签名 (implementation signature) ,但这个签名不能被直接调用。尽管在函数声明中,在一个必须参数后,声明了两个可选参数,它依然不能被传入两个参数进行调用。

function makeDate(timestamp: number): Date;
function makeDate(m: number, d: number, y: number): Date;
function makeDate(mOrTimestamp: number, d?: number, y?: number): Date {
  if (d !== undefined && y !== undefined) {
    return new Date(y, mOrTimestamp, d);
  } else {
    return new Date(mOrTimestamp);
  }
}
const d1 = makeDate(12345678);
const d2 = makeDate(5, 5, 5);
const d3 = makeDate(1, 3);

// 没有需要 2 参数的重载,但存在需要 1 或 3 参数的重载。
  • 函数重载注意签名的兼容性和实现
function fn(x: boolean): void;
// Argument type isn't right
function fn(x: string): void;//此重载签名与其实现签名不兼容。
function fn(x: boolean) {}
function fn(x: string): string;
// Return type isn't right
function fn(x: number): boolean;//此重载签名与其实现签名不兼容。
function fn(x: string | number) {
  return "oops";
}
function fn(x: string): void;
function fn() {
  // ...
}
// 应有 1 个参数,但获得 0 个。ts(2554) 01.ts(1, 13): 未提供 "x" 的自变量。
fn();
// 函数的重载: 函数的名称相同, 但是参数不同的几个函数, 就是函数的重载
function add(num1: number, num2: number): number; // 没函数体
function add(num1: string, num2: string): string;

function add(num1: any, num2: any): any {
  if (typeof num1 === 'string' && typeof num2 === 'string') {
    return num1.length + num2.length
  }
  return num1 + num2
}

const result = add(20, 30)
const result2 = add("abc", "cba")
console.log(result)
console.log(result2)

// 在函数的重载中, 实现函数是不能直接被调用的
// add({name: "why"}, {age: 18})

export {}
# 函数剩余参数问题

as const 也是类型断言的一种 这被称为const断言。const断言告诉编译器为表达式推断出它能推断出的最窄或最特定的类型。如果不使用它,编译器将使用其默认类型推断行为,这可能会导致更广泛或更一般的类型。

请注意,它被称为“断言”,而不是“强制转换”。

const args = [8, 5];
// const args: number[]
const angle = Math.atan2(...args); // error! Expected 2 arguments, but got 0 or more.
console.log(angle);

编译器看到const args = [8, 5];,并推断出number[]的类型。这是一个由0个或更多number类型的元素组成的可变数组。编译器不知道有多少或哪些元素。这样的推断通常是合理的;通常,数组内容意味着要以某种方式进行修改。如果有人想写args.push(17)或args[0]++,他们会很乐意使用number[]类型。

不幸的是,下一行Math.atan2(…args)导致了一个错误。Math.atan2()函数正好需要两个数值参数。但是编译器只知道args是一个数字数组。它完全忘记了有两个元素,因此编译器抱怨说,当它只需要两个参数时,您正在用“0或更多”参数调用Math.atan2()。

将其与as const的代码进行比较:

const args = [8, 5] as const;
// const args: readonly [8, 5]
const angle = Math.atan2(...args); // okay
console.log(angle);

现在编译器推断args属于readonly [8, 5]类型。。。一个readonly元组,其值正好是按此顺序排列的数字8和5。具体来说,args.length被编译器精确地称为2。

这就足够下一行使用Math.atan2()了。编译器知道Math.atan2(…args)与Math.atan2(8, 5)相同,这是一个有效的调用。

  • tsconfig.json :2021年默认生成的target是es5,会导致上述代码运行错误:Type 'string' is not an array type.需要开启es2015以上来修改
{
  "compilerOptions": {
    /* Visit https://aka.ms/tsconfig.json to read more about this file */
    /* Basic Options */
    // "incremental": true,                         /* Enable incremental compilation */
    "target": "es2015",                                /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', 'ES2021', or 'ESNEXT'. */
    "module": "commonjs",                          
     "downlevelIteration": true,                  /* Provide full support for iterables in 'for-of', spread, and destructuring whe
    "forceConsistentCasingInFileNames": true        /* Disallow inconsistently-cased references to the same file. */
  }
}
# 写一个好的函数重载的一些建议

这个函数代码功能实现了,也没有什么报错,但我们不能传入一个可能是字符串或者是数组的值,因为 TypeScript 只能一次用一个函数重载处理一次函数调用。

function len(s: string): number;
function len(arr: any[]): number;
function len(x: any) {
  return x.length;
}
len(""); // OK
len([0]); // OK


len(Math.random() > 0.5 ? "hello" : [0]);
// 没有与此调用匹配的重载。
//   第 1 个重载(共 2 个),“(s: string): number”,出现以下错误。
//     类型“number[] | "hello"”的参数不能赋给类型“string”的参数。
//       不能将类型“number[]”分配给类型“string”。
//   第 2 个重载(共 2 个),“(arr: any[]): number”,出现以下错误。
//     类型“number[] | "hello"”的参数不能赋给类型“any[]”的参数。
//       不能将类型“string”分配给类型“any[]”。ts(2769)
// 01.ts(3, 10): 针对此实现的调用已成功,但重载的实现签名在外部不可见。

因为两个函数重载都有相同的参数数量和相同的返回类型,我们可以写一个无重载版本的函数替代:

function len(x: any[] | string) {
  return x.length;
}

这样函数就可以传入两个类型中的任意一个了。

尽可能的使用联合类型替代重载

  • ts使用this作为参数
//函数内This 的声明
interface User { 
  admin: boolean 
}

interface DB { 
  filterUsers(filter: (this: User) => boolean): User[]; 
}

const db:DB = { 
  filterUsers: (filter: (this: User) => boolean) => { 
   
    let user1 = { admin: true }
  let user2 = { admin: false }
      return [user1, user2] 
} 
}
//这里不能使用箭头函数
const admins = db.filterUsers(function (this: User) { 
  return this.admin; 
})

console.log(admins)

注意需要使用 function 的形式而不能使用箭头函数

# 函数声明法

函数声明法创建函数是最常用的函数定义法。使用function关键字和函数名去定义一个函数。

function add(n1:number,n2:number):number{
	return n1+n2
}

# 函数表达式法

函数表达式法是将一个函数赋值给一个变量,这个变量名就是函数名。通过变量名就可以调用函数了。这种方式定义的函数,必须在定义之后,调用函数。下面例子中等号右边的函数没有函数名,称为匿名函数。

var add = function(n1:number,n2:number):number{
	return n1+n2
}

console.log(add(1,4))
const func1: (str: string) => number = str => {
  return parseInt(str, 10);
};

func1的函数声明

这里的 (str: string) => number中的=>实际上是返回的意思而不是箭头函数的中的箭头的作用

# 箭头函数

var add = (n1:number,n2:number):number=>{
	return n1+n2
}

console.log(add(1,4))

函数返回值关键字可以是number string之类的也可以无返回值void或者永远不能全部执行结束的never类型

function errorEmitter(): never {
  while(true) {}
}
  • 还可以使用接口的方式进行定义
interface Isum{
	(age:number,time?:number):number;
}

const fun:Isum=(a,b)=>{
	return a+b
}
最后更新: 5/22/2024, 8:24:41 AM