函数类型

TS定义函数类型需要定义输入类型和输出类型,其中输出类型可以忽略不写,因为TS能够根据返回的语句自动推断出返回的类型,这与Go语言自动推断类型很像。

定义简单的函数

// 定义输入类型和输出类型
function add(val1: number, val2: number): number {
  return val1 + val2
}

// 定义输入类型而不定义输出类型,将自动推到出输出类型
function add1(val1: number, val2: number) {
  return val1 + val2
}

返回void类型

// 写输出类型为void类型
function get(): void {
    console.log("hello world")
}

// 不写输出类型,也能自动推导出void类型
function get() {
    console.log("hello world")
}

箭头函数

const add = (val1: number, val2: number): number => {
    return val1 + val2
}

可选参数

const add = (val1: number, val2: number, val3?: number): number => {
    return val1 + val2
}

console.log(add(1,2))
console.log(add(1,2,3))

默认参数

function add(val1: number = 1, val2: number = 2){
    return val1 + val2
}

console.log(add()) // 3

类型别名定义函数类型

type MyFunctionType = (param1:string,param2:number) => boolean

const MyFunction:MyFunctionType = (param1,param2) => {
    // 判断param1和param2的类型是否相等
    if(typeof param1 === typeof param2){
        return true
    }
    return false
}

接口定义函数类型

interface MyFunctionInterface {
    (param1: number, param2: string): boolean;
}

const MyFunction: MyFunctionInterface = (param1, param2) => {
    // 判断param1和param2的类型是否相等
    if (typeof param1 === typeof param2) {
        return true
    }
    return false
}

接口

在 TypeScript 中,interface(接口)用于定义对象的类型。它可以描述对象的结构,包括属性和方法。

定义 interface 一般首字母大写,代码如下:

interface Person {
  name: string;
  age: number;
  sayHello: () => void;
}

注意:当定义完interface后,属性和类型定义必须完全一致

// 例如少写了sayHello方法,提示类型报错 "{ name: string; age: number; }" 中缺少属性 "sayHello",但类型 "Person" 中需要该属性。
let person: Person = {
    name: 'Tom',
    age: 20,
};

// 当多添加字段phone的时候,提示类型报错 不能将类型“{ name: string; age: number; sayHello: () => void; phone: string; }”分配给类型“Person”。对象字面量只能指定已知属性,并且“phone”不在类型“Person”中。
let person: Person = {
    name: 'Tom',
    age: 20,
    sayHello: function () {
        console.log('Hello ' + this.name);
    },
    phone: '123-456-7890'
};

可选属性

在 TypeScript 的接口中,我们可以定义可选属性。可选属性表示该属性可以存在,也可以不存在,对象可以选择性地包含这些属性。

我们可以通过在属性名后加上问号(?)来定义可选属性。下面是一个示例:

interface Person {
  name: string;
  age?: number;
  sayHello: () => void;
}

在上面的示例中,age 属性被定义为可选属性,即对象可以有也可以没有 age 属性。

当我们创建对象时,可以选择性地包含可选属性。下面是一个示例:

const tom: Person = {
  name: "Tom",
  sayHello: () => {
    console.log(`Hello, my name is ${this.name}`);
  }
};

在上面的示例中,我们创建了一个名为 tom 的对象,它包含了 name 属性和 sayHello 方法,但是没有 age 属性。

索引签名(自定义属性)

在 TypeScript 中,接口(interface)可以定义索引签名,用于描述对象的索引类型和对应的属性类型

索引签名允许对象具有动态属性,这意味着可以使用可变的键来访问和设置属性。有两种类型的索引签名:字符串索引签名和数字索引签名。

以下是一个使用字符串索引签名的示例:

interface Person {
  name: string;
  age: number;
  [key: string]: string | number;
}

const person: Person = {
  name: "Tom",
  age: 25,
  Email: "123456@qq.com",
  gender: "Man"
};

console.log(person.name); // 输出: John
console.log(person.age); // 输出: 25
console.log(person.Email); // 输出: 123456@qq.com
console.log(person.gender); // 输出: Man

在上述代码中,我们定义了一个 Person 接口,其中的 key 是字符串类型的索引签名,表示可以使用任意字符串作为对象的属性名,对应的属性值类型是 stringnumber

通过使用字符串索引签名,我们可以在创建对象时动态地添加任意的属性,并且保证这些属性的值的类型是 stringnumber

另外,还可以使用数字索引签名来定义数组类型的接口,以下是一个使用数字索引签名的示例:

interface NumberArray {
  [index: number]: number;
}

const numbers: NumberArray = [1, 2, 3, 4, 5];

console.log(numbers[0]); // 输出: 1
console.log(numbers[1]); // 输出: 2
console.log(numbers[2]); // 输出: 3

只读属性

在 TypeScript 中,可以使用 readonly 关键字来定义只读属性,它用于确保某个属性只能在创建对象时进行赋值,而不能在之后进行修改。

下面是一个使用 readonly 定义只读属性的示例:

interface Person {
  readonly name: string;
  age: number;
}

const person: Person = {
  name: "Tom",
  age: 25
};

console.log(person.name); // 输出: Tom

// 以下代码会引发错误
person.name = "Dadong"; // 不能修改只读属性

person.age = 30; // 可以修改非只读属性
console.log(person.age); // 输出: 30

在上述代码中,我们定义了一个 Person 接口,其中的 name 属性使用 readonly 关键字标记为只读属性。在创建对象 person 时,可以对只读属性进行赋值,但之后无法修改。

在使用只读属性时,需要注意以下几点:

  1. 只读属性必须在对象的创建时进行赋值,之后不能再对其进行修改。

  2. 只读属性只能在对象内部进行赋值,而不能在外部进行赋值。

  3. 如果将只读属性作为函数参数或返回值,那么在函数内部也不能对其进行修改。

  4. 通过使用 readonly 关键字,可以提升代码的安全性,并确保对象的某些属性不会在运行时被意外修改。

接口的继承

在 TypeScript 中,接口(interface)可以通过继承(extends)其他接口来扩展其属性和方法。

接口的继承使用 extends 关键字,可以继承单个或多个其他接口。被继承的接口称为父接口,继承它的接口称为子接口。

下面是一个使用接口继承的示例:

interface Animal {
  name: string;
  sound: string;
}

interface Dog extends Animal {
  breed: string;
}

const myDog: Dog = {
  name: "Max",
  sound: "Woof",
  breed: "Labrador"
};

console.log(myDog.name); // 输出: Max
console.log(myDog.sound); // 输出: Woof
console.log(myDog.breed); // 输出: Labrador

在上述代码中,我们定义了一个 Animal 接口,它包含 namesound 属性。然后我们定义了一个 Dog 接口,它继承了 Animal 接口,并添加了一个 breed 属性。

通过继承 Animal 接口,Dog 接口拥有了 namesound 属性,同时还有自己的 breed 属性。

我们创建了一个 myDog 对象,它符合 Dog 接口的定义,并可以访问 namesoundbreed 属性。

可以使用继承来创建更具体的接口,通过继承的方式复用已有的接口定义,并在其基础上添加、修改或扩展属性和方法,使代码更加模块化和可维护。

接口合并

在 TypeScript 中,可以通过接口合并来扩展已有接口的定义。当多个同名接口出现时,它们会自动合并为一个接口。

接口合并可以用于在不同的地方对同一个接口进行扩展,以实现接口的分离和模块化。

以下是一个示例:

interface Animal {
  name: string;
  sound: string;
}

interface Animal {
  age: number;
}

const myAnimal: Animal = {
  name: "Max",
  sound: "Woof",
  age: 3
};

console.log(myAnimal.name); // 输出: Max
console.log(myAnimal.sound); // 输出: Woof
console.log(myAnimal.age); // 输出: 3

在上述代码中,我们定义了两个同名的接口 Animal,它们分别包含不同的属性。当我们创建一个 myAnimal 对象时,它会同时具有两个接口的属性。

接口合并的规则如下:

  1. 属性的类型必须匹配。如果同名属性的类型不一致,则会产生编译错误。

  2. 同名函数接口会被合并为一个函数接口。合并后的函数接口包含了所有同名函数的定义,且函数重载也会被保留。

  3. 同名方法签名会被合并为一个方法签名。合并后的方法签名包含了所有同名方法签名的参数和返回类型。

  4. 接口合并在 TypeScript 中提供了一种灵活的方式来对接口进行扩展和组合,可以根据需求灵活使用。