函数

  1. 默认参数 x: number = 1
  2. 可选参数 x?: number
  3. 剩余参数 ...args: 类型[]
  4. 多种类型 x: number | string
    1. let myAdd = function (x: number, y: number=1, ...args: any[]): number {
    2. console.log(args); //[3, '4', false]
    3. return x + y
    4. }
    5. myAdd(1, 2, 3, '4', false)

    this

    在Typescript中,必须要明确的指定this的类型(严格模式下) ```typescript type objType = {person: (n: string) => void, myname: string}; //this指向objType 或 Window,此处this不占形参位置 function person(this: Window | objType , name: string):void { this.myname = name; console.log(this.myname); }

//window上指定this和调用 window.person = person; //将person添加到window对象上 window.person(‘window name’);//调用

//对象形式指定this和调用 let obj:objType = { person, myname: ‘’ }; obj.person(‘obj name’);

单单是上面的代码是有问题的,我们还需要创建一个类型声明文件**global.d.ts(一般的全局属性拓展都加在该文件上)**,为window对象上扩展两个属性person、myname;
```typescript
interface Window {
  person: (n: string) => void;
  myname: string;
}

定义对象的函数属性时,只要实际调用中 this 的指向与指定的 this 指向不同,TypeScript 就能发现 this 指向的错误

interface ObjType2 {
  name: string;
  say: (this: ObjType2) => void;
}
let obj2:ObjType2 = {
  name: 'obj2',
  say() {
      console.log(this.name);
  }
} 

obj2.say(); // ok

let t11 = obj2.say;
t11(); //error   -ObjType2中say方法指定this,而此处this指向window

注意:
1. 显式声明函数的返回值类型为 undfined,则会出现错误提示,如果没有返回值,我们用void表示;
2. 注意:显式注解函数中的 this 类型,它表面上占据了第一个形参的位置,但并不意味着函数真的多了一个参数,因为 TypeScript 转译为 JavaScript 后,“伪形参” this 会被抹掉,这算是 TypeScript 为数不多的特有语法。

函数重载

函数重载: 函数名相同, 而形参不同的多个函数
在JS中, 由于弱类型的特点和形参与实参可以不匹配, 是没有函数重载这一说的 但在TS中, 与其它面向对象的语言(如Java)就存在此语法

/* 
函数重载: 函数名相同, 而形参不同的多个函数
需求: 我们有一个add函数,它可以接收2个string类型的参数进行拼接,也可以接收2个number类型的参数进行相加 
*/

// 重载函数声明
function add(x: string, y: string): string
function add(x: number, y: number): number

// 定义函数实现
function add(x: any, y: any): any {
  return x + y
}

//默认回去找对应的重载函数声明
console.log(add(1, 2)) 
console.log(add('a', 'b'))
// console.log(add(1, 'a')) // error

泛型(Generic)

指在定义函数、接口或类的时候,不预先指定具体的类型(返回值、参数、属性的类型),而在使用的时候再指定具体类型的一种特性。

//如果我们使用any来代替泛型 则不会有提示
function test<T>(arg: T): T {
  return arg;
}

const num = test(10) //直接传递参数使用,类型会由TS自动推断出来
const str = test<string>('Dan')
console.log(num.toFixed()); //会有相对应的方法提示 编译器知道这是个number类型
console.log(str.split('')); //会有相对应的方法提示 编译器知道这是个string类型

这里的<T>就是泛型,T是我们给这个类型起的名字(不一定非叫T),设置泛型后即可在函数中使用T来表示该类型。所以泛型其实很好理解,就表示某个类型。

多个泛型的函数

可以同时指定多个泛型,泛型间使用逗号隔开:

function test<T, K>(a: T, b: K): K{
    return b;
}

test<number, string>(10, "hello");

泛型接口

// 指定一个泛型接口 需要被定义类型
interface IbaseCRUD<T> {
  data: T[]
  add: (t: T) => void
  getById: (id: number) => T
}

//定义一个类 用来做泛型接口的类型
class User {
  id?: number; //id主键自增
  name: string; //姓名
  age: number; //年龄

  constructor(name: string, age: number) {
    this.name = name
    this.age = age
  }
}

//定义一个类 使用接口IbaseCRUD
//接口的类型由User决定
class UserCRUD implements IbaseCRUD<User> {
  //实现接口中需要的属性 data & add & getById
  //data为User类型的数组,数组中每一项都要符合User定义 { name: str, age: num, id?: num}
  data: User[] = []

  add(user: User): void {
    //...user 这里要接收name: string, age: number
    user = { ...user, id: Date.now() }
    this.data.push(user)
    console.log('保存user', user.id)
  }

  getById(id: number): User {
    //找不到是undefined || 返回一个User类型
    return this.data.find(item => item.id === id) || { name: 'dan', age: 18, id: 1 }
  }
}


const userCRUD = new UserCRUD()
userCRUD.add(new User('tom', 12))
userCRUD.add(new User('tom2', 13))
console.log(userCRUD.data)
// [
//   { name: 'tom', age: 12, id: 1646107493799 },
//   { name: 'tom2', age: 13, id: 1646107493800 }
// ]
console.log(userCRUD.getById(Date.now()));

泛型类

在定义类时, 为类中的属性或方法定义泛型类型 在创建类的实例时, 再指定特定的泛型类型

class MyClass<T>{
  prop: T;
  constructor(prop: T) {
    this.prop = prop;
  }
}

const numclass = new MyClass<number>(11)
const strclass = new MyClass<string>("Dan")

泛型约束

如果我们直接对一个泛型参数取 length 属性, 会报错, 因为这个泛型根本就不知道它有这个属性

// 没有泛型约束
function fn <T>(x: T): void {
  // console.log(x.length)  // error
}

使用泛型约束来实现

interface Lengthwise {
  length: number; //必须有length属性 length属性返回值是num
}

// 指定泛型约束
//使用T extends MyInter表示泛型T必须是MyInter的子类
function fn<T extends Lengthwise>(x: T): void {
  console.log(x.length)
}
fn("AAAA")//4
fn([1, 2, 3]) //3