「TypeScript」接口,数组,函数


接口(Interface)

使用接口(Interfaces)来定义对象的类型。

在面向对象语言中,接口(Interfaces)是一个很重要的概念,它是对行为的抽象,而具体如何行动需要由类(classes)去实现(implement)。
TypeScript 中的接口是一个非常灵活的概念,除了可用于对类的一部分行为进行抽象以外,也常用于对「对象的形状(Shape)」进行描述。

interface List {
  id: number;
  name: string;
}
interface Result {
  data: List[];
}
let result: Result = [{ id: 1, name: "Tom" }]; // result的形状必须与接口一致
  • 定义的变量比接口少了一些属性或者多一些属性是不允许的;
  • 赋值的时候,变量的形状必须和接口的形状保持一致

可选属性

interface List {
  id: number;
  name: string;
  age?: number; // 可选属性: 该属性可以不存在
}

任意属性

一个接口允许有任意的属性:

interface List {
  id: number;
  name: string;
  [x: string]: any; // 任意属性取 string 类型的值
}

注:一旦定义了任意属性,那么确定属性和可选属性的类型都必须是它的类型的子集,比如任意属性的类型为 string,那么该接口不能存在 number,boolean 等类型的属性。

只读属性

interface List {
  readonly id: number;
  name: string;
}
let tom: List = {
  id: 1,
  name: "Tom",
};
tom.id = 2; // error

let Tony: List = {
  name: "Tony",
};
Tony.id = 2; // error

只读的约束存在于第一次给对象赋值的时候,而不是第一次给只读属性赋值的时候

实践

function render(result: Result) {
  result.data.forEach((item) => {
    console.log(item.id, item.name);
  });
}
let result = {
  data: [
    { id: 1, name: "Tom" },
    { id: 2, name: "Amy" },
  ],
};
render(result); // 正常输出

let result2 = {
  data: [
    { id: 1, name: "Tom", gender: "male" },
    { id: 2, name: "Amy" },
  ],
};
render(result2); // 正常输出

render({
  data: [
    { id: 1, name: "Tom", gender: "male" },
    { id: 2, name: "Amy" },
  ],
}); // 则会有类型检验的错误

// 类型断言绕过类型判断
render({
  data: [
    { id: 1, name: "Tom", gender: "male" },
    { id: 2, name: "Amy" },
  ],
} as Result);

数组

类型+[]

let fibonacci: number[] = [1, 1, 2, 3, 5];

数组泛型

let fibonacci: Array<number> = [1, 1, 2, 3, 5];

接口表示数组

基本不会这么使用。

interface NumberArray {
  [index: number]: number;
}
let fibonacci: NumberArray = [1, 1, 2, 3, 5];

类数组

函数中的arguments 实际上是一个类数组,不能用普通的数组的方式来描述:

function sum() {
  let args: number[] = arguments;
} // error

function sum() {
  let args: {
    [index: number]: number;
    length: number;
    callee: Function;
  } = arguments;
} // 除了约束当索引的类型是数字时,值的类型必须是数字之外,也约束了它还有 length 和 callee 两个属性。

函数

在 JavaScript 中,有两种常见的定义函数的方式——函数声明(Function Declaration)和函数表达式(Function Expression)。

函数声明

function sum(x: number, y: number): number {
  return x + y;
} // 需要对输入输出的类型进行约束

sum(1, 2, 3); // error
sum(1); // error

输入多余的(或者少于要求的)参数,是不被允许的

函数表达式

let mySum = function (x: number, y: number): number {
  return x + y;
};

事实上,上面的代码只对等号右侧的匿名函数进行了类型定义,而等号左边的 mySum,是通过赋值操作进行类型推论而推断出来的。更精确的写法应该是:

let mySum: (x: number, y: number) => number = function (
  x: number,
  y: number
): number {
  return x + y;
};

注:在 TypeScript 的类型定义中,=> 用来表示函数的定义,左边是输入类型,需要用括号括起来,右边是输出类型。

接口定义函数

interface SearchFunc {
  (source: string, subString: string): boolean;
}

let mySearch: SearchFunc;
mySearch = function (source: string, subString: string) {
  return source.search(subString) !== -1;
};

可选参数

可选参数必须接在必需参数后面,即可选参数后面不允许再出现必需参数了

function buildName(firstName: string, lastName?: string) {}

参数默认值

function buildName(firstName: string, lastName: string = "Cat") {
  return firstName + " " + lastName;
}

剩余参数(rest 参数)

function push(array: any[], ...items: any[]) {
  items.forEach(function (item) {
    array.push(item);
  });
}
let a = [];
push(a, 1, 2, 3);

注:rest 参数只能是最后一个参数。

重载

重载允许一个函数接受不同数量或类型的参数时,作出不同的处理。

function reverse(x: number): number;
function reverse(x: string): string;
function reverse(x: number | string): number | string | void {
  if (typeof x === "number") {
    return Number(x.toString().split("").reverse().join(""));
  } else if (typeof x === "string") {
    return x.split("").reverse().join("");
  }
}

文章作者: 阿汪同学
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 阿汪同学 !
评论
  目录