Day14:【TypeScript 学起来】Interfaces(介面) 笔记整理

终於来到 interface,觉得这个算是颇重要的一趴,让我们看下去。这大概是我最认真做笔记的一篇 哈哈。 因为一开始学一直看到他,从一开始不懂到大概了解,到後面更了解一点,所以笔记也加加改改的,如果有错也欢迎留言告诉我~


interfaces(介面)

在 TypeScript 中,我们使用介面(Interfaces)来定义物件的型别,对物件的形状(shape)进行描述,包含了有哪些属性 (properties) 和方法 (methods)。

在物件导向程序语言中,介面(Interfaces)是一个很重要的概念,它是对行为的一种抽象,而具体如何行动则需要由类别(class)去实现(implement)。 class 後面会再笔记~


定义一个 interfaces

✅ 定义一个介面 Person,接着定义了一个变数 iris,它的型别是 IPerson。就约束了 iris 的形状必须和介面 IPerson 一致。 介面一般首字母大写如 Person, 则有些语言会建议加上I字首如IPerson 来表示。赋值的时候,变数的形状必须和介面的形状保持一致。

interface IPerson {
    name: string;
    age: number;
}

const iris: IPerson = {
    name: 'Iris',
    age: 18
};

❌ 变数比介面多或少一些属性是不允许的。

const iris: IPerson = {
    name: 'Iris'
};
//error: Property 'age' is missing in type '{ name: string; }' but required in type 'Person'.ts(2741)


const iris: IPerson = {
    name: 'Iris',
    age: 18,
    gender: 'female'
};
//error: Type '{ name: string; age: number; gender: string; }' is not assignable to type 'Person'.
//Object literal may only specify known properties, and 'gender' does not exist in type 'Person'.

如果不想写年龄可以吗 - 可选属性

在不需要完全匹配的属性後面加上?,表示该属性可以不存在。如下面例子,少了age 属性赋值也不会报错。

interface IPerson {
    name: string;
    age?: number;
}

const iris: IPerson = {
    name: 'Iris'
};

但还是一样不能新增减少未定义的属性

如果一样想要新增性别,还是会报错。

interface IPerson {
    name: string;
    age?: number;
}

const iris: IPerson = {
    name: 'Iris',
    gender: 'female'
};
//error: Type '{ name: string; age: number; gender: string; }' is not assignable to type 'Person'.
//Object literal may only specify known properties, and 'gender' does not exist in type 'Person'.

如果要新增任意属性 怎麽新增呢 - Index Signatures

Index Signatures 就是当我们有时候事先并不知道属性名称,或是未来会新增属性,但知道值的形状。我们就可以使用 Index Signatures 来描述值可能的型别。

如以下例子, 使用[propName: string]定义了key, 属性名称为字串,赋值时可自行命名。对应的值 value 的型别为 string 或者 number 或是 undefined 。

interface IPerson {
    name: string;
    age?: number;
    [propName: string]: string | number | undefined;
}

const iris5: IPerson = {
    name: 'Iris',
    gender: 'female'  
};

针对 Index Signatures, 我也会再写一篇笔记唷,他有些用法新手谁知道啦XD


唯读属性 readonly

可以用 readonly 定义唯读属性,唯读的约束存在於第一次给「物件」赋值的时候,而不是第一次给「唯读属性」赋值的时候。

interface IPerson {
    readonly id: number; //唯读约束
    name: string;
    age?: number;
    [propName: string]: any;
}

const iris: IPerson = {
    id: 89757, //如果没给则报错 Property 'id' is missing in type 
    name: 'Iris',
    gender: 'female'
};

如果我们来修改id, 这时候就会报错:

iris.id = 9527;

// error: Cannot assign to 'id' because it is a read-only property.

interface 应用在函式中

greetPerson 函式中, person 参数型别为 IPerson, 便可以取用 IPerson 的属性了。

interface IPerson {
    readonly id: number;
    name: string;
    age?: number;
    [propName: string]: any;
}

const iris: IPerson = {
    id: 89757,
    name: 'Iris',
    gender: 'female'
};

const greetPerson = (person : IPerson) => {
    console.log(`hi,${person.name}!`);
}

greetPerson(iris);//hi,Iris!

Extending Types 扩展

interface 也可以被扩展。比如说我们有 BasicAddress 的型别, 但如果专案中某个区域地址多了 unit,我们就可以使用 extends 来多增加 unit 的栏位,是蛮方便+简洁的~

interface BasicAddress {
  name?: string;
  street: string;
  city: string;
  country: string;
  postalCode: string;
}
 
interface AddressWithUnit extends BasicAddress {
  unit: string;
}

interface 也可以扩展多个 interface:

interface Colorful {
  color: string;
}
 
interface Circle {
  radius: number;
}
 
interface ColorfulCircle extends Colorful, Circle {
    background: string;
}
 
const cc: ColorfulCircle = {
  color: "red",
  radius: 42,
  background: "white"
};

interface 可以重复定义

以下例子,可以看到, 当少了gender属性会报错。因为TS已把 IPerson 的 interface 都合并起来了。

interface IPerson {
    name: string;
}

interface IPerson {
    age?: number;
}

interface IPerson {
    gender: string;
}

const iris:IPerson = {  
    name: 'Iris',
    age: 18
}

//error:Property 'gender' is missing in type '{ name: string; age: number; }' but required in type 'IPerson6'

重复相同的interface 名称, TS会进行合并,等同於:

interface IPerson {
    name: string;
    age: number;
    gender: string;
}

interface 还可以定义阵列及函式

我们都知道interface 可以来定义 object,还可以定义 object 的子型别,包括阵列及函式。

Array:

interface INumberArray {
    [index: number]: number;
}
const list: INumberArray = [1, 1, 2, 3, 5];

Function:

interface IPersonFunc {
  (name: string, age: number): void;
}

interface 可以 function overload

interface 也可以定义 function overload。 function overload 是指扩充一个函式可以被执行的形式。

interface IPoint {
    getDist(): number;
    getDist(x?: number): number;
}

const point:IPoint = {
    getDist(x?: number) {
         if (x && typeof x == "number") {
             return x;
         } else {
             return 0;
         }
    }
}

console.log(point.getDist(20)); //20
console.log(point.getDist()); //0

耶,觉得更了解 interfaces 了。赞赞, 下篇来介绍跟 interfaces 很像的 Type Aliases(型别别名) 。 他跟 interfaces 又有什麽不一样呢?


参考资料

https://willh.gitbook.io/typescript-tutorial/basics/type-of-object-interfaces
https://basarat.gitbook.io/typescript/type-system/interfaces


<<:  自动化 End-End 测试 Nightwatch.js 之踩雷笔记:Page Objects

>>:  [Day 14] 阿嬷都看得懂的 style 标签怎麽用

Day 3 就是你了!

有时候,我们都太天真的想像着美好,然而降临我们面前的不只是美好,有时是想不到的冲突,或者双方同时出现...

Day24:【技术篇】设定自己的GitHub Pages

一、前言   网路上有很多创建个人 GitHub Pages 的教学文章,这边就先跳过此环节与相关原...

[Day17] NLP会用到的模型(二)-LSTM

一. RNN会造成的问题 前一天看过了RNN的训练流程,他是非常长一串,若今天我们需训练一个非常长的...

Progressive Web App 跨平台安装上架 (30)

Progressive Web App 跨平台安装 Progressive Web App 本身就具...

[第一只羊] 动物园派对桌游设计之迷雾森林

关於迷雾森林故事 序 很久很久以前 在森林的深山林里 有着一群喜欢开趴的动物 就是大家俗称的趴踢 ...