TS 对象类型(接口)和数组类型

2,137 阅读6分钟

对象类型---接口

在 TypeScript 中,我们使用接口(Interfaces)来定义对象的类型。

在面向对象语言中,接口是对行为的抽象,常用于对「对象的形状」进行描述,接口可以理解为是对象的一种约束。

简单的例子

定义接口类型不需要赋值,在创建变量使用接口类型定义类型时赋值。

interface Person {
    name: string;
    age: number;
}
let people: Person = {
    name: 'jzx',
    age: 26
};

上述代码,定义了一个接口 Person,接着定义了一个变量 people,它的类型是 Person。这样就约束了 people的形状必须和接口 Person 一致。

所谓变量的形状必须和接口的形状保持一致就是创建的变量在赋值时比接口少了一些属性是不允许的,多一些属性也是不允许的。

interface Person {
    name: string;
    age: number;
}
let people: Person = {
    name: 'jzx'
};
//编译报错 Type '{ name: string; }' is not assignable to type 'Person'.
//   Property 'age' is missing in type '{ name: string; }'.

interface Person {
    name: string;
    age: number;
}
let people: Person = {
    name: 'jzx',
    age: 25,
    player:'actress'
};
//编译报错  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'.

image.png

image.png

定义多个同类型的接口,在TS中会将该接口中所有的成员合并,且接口中的成员不能有实际的成员值,接口是抽象的主要用于对「对象的形状」进行描述,未来创建的变量使用该类型就会实现这个对象的功能。

interface myInterface{
    name:string
}

interface myInterface{
    age:number
}

let obj:myInterface={
    name:'maoamo',
    
}

image.png

image.png

interface myInterface{
    name:string;
}

interface myInterface{
    age:number;
}

let obj:myInterface={
    name:'maoamo',
    age:6
}

console.log(obj);

image.png

可选属性

当希望不要完全匹配一个形状,那么可以用可选属性

interface SquareConfig {
  color?: string;
  width?: number;
}
  let config:SquareConfig={
    color:'red',
    height:'10'
  }
  //编译报错 Type '{ color: string; height: string; }' is not assignable to type 'SquareConfig'.
//   Object literal may only specify known properties, and 'height' does not exist in type 'SquareConfig'.

可选属性的含义是创建对象时该属性可以不存在,在可选属性名字定义的后面加一个?符号,但是仍然不允许添加未定义的属性。

image.png

只读属性

一些对象属性只能在对象刚刚创建的时候修改其值,可以在属性名前用 readonly来指定只读属性。

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

//编译报错  对tom进行赋值的时候,没有给id赋值
let tom: Person = {
    name: 'Tom',
};

let jerry: Person = {
    id: 89757,
    name: 'jerry',
};
//编译报错 由于id是只读属性,不能再修改
jerry.id = 9527;

image.png

image.png

ps:只读的约束存在于第一次给对象赋值的时候,而不是第一次给只读属性赋值的时候。只读属性也是确定属性,在创建对象时必须存在。

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

let jerry: Person = {
    id: 89757,
    name: 'jerry',
};
jerry={
    id:1213168,
    name:'gloria'
}
//编译不报错

虽然只读属性初始化后,又被赋值会编译报错,但是可以修改对象整体的引用。

image.png

任意属性

当一个对象使用接口描述其未来的功能时,必选参数不能少也不能多给对象追加成员,也会编译报错。必须按照给定的成员来创建对象的成员。解决方法就是在定义对象类型的时除了必选属性还可以添加任意属性。

interface Person{
    name:string;
    age:number;
    height?:number;
}
let p1:Person={
    name:'jzx',
    age:26,
}
p1.player='actress';

image.png

一个接口只能定义一个任意属性,一旦定义了任意属性,那么确定属性和可选属性的类型都必须是它的类型的子集

interface Person {
    name: string;
    age?: number;
    [propName: string]: string;
}

let tom: Person = {
    name: 'Tom',
    age: 25,
    gender: 'male'
};

image.png

string类型的子集不包含number类型

interface Person {
    name: string;
    age?: number;
    [propName: string]: any;
    //[propName: string]: any表示创建的对象的属性名的类型是字符串和属性值类型是任意类型
}

let p1:Person={
    name:'jzx',
    age:26,
}
p1.player='actress';
console.log(p1);

image.png

一个接口中只能定义一个任意属性。如果接口中有多个类型的属性,则可以在任意属性中使用联合类型:

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

let tom: Person = {
    name: 'Tom',
    age: 25,
    gender: 'male'
};

数组类型

数组类型定义方式

在 TypeScript 中,数组类型有多种定义方式。

第一种:可以在元素类型后面接上 [],表示由此类型元素组成的一个数组。

let arr:[] = [];//表示arr是数组类型且是一个空数组
let list: any[]; //数组的元素可以是任意值 
let arr1: number[] = [1, 2, 3, 5];//表示arr1是数组类型且数组的元素只能是number数字类型

//Type 'string' is not assignable to type 'number'  编译会报错数组中的元素有字符串string类型
arr= [1, '1', 2, 3, 5];


//编译报错 Argument of type '"8"' is not assignable to parameter of type 'number'.
arr.push('8');
//push 方法也只允许传入 number 类型的参数

push 方法只允许传入 number 类型的参数,但是却传了一个 "8" 类型的参数,所以报错了。

定义了类型,数组的项中不允许出现其他的类型,数组的一些方法的参数也会根据数组在定义时约定的类型进行限制。

第二种:使用泛型 Array<类型>来表示数组,尖括号中就是指定数组元素的类型。

let arr1: Array<number> = [1, 1, 2, 3, 5];//正确
let arr2: Array<number> = [1, '1', 2, 3, 5];//编译报错
let arr3: Array<string> = ["hello","h5"];//正确
let arr4: Array<string> = [1,"h5"];//编译报错

用接口表示数组

接口可以规定数组中元素的索引类型和元素类型用来描述数组类型。(不常用)

//规定以number为数组元素的索引下标、string为数组中元素的类型。
interface NumberArray {
    [index:number]: string;
}
let fibonacci: NumberArray = ["John","Bran"];

用接口描述数组没太大必要,但类数组不能用普通的数组的方式来描述,需要使用接口来表示类数组的形状

类数组不是数组类型,比如 arguments。常用的类数组都有自己的接口定义,在TypeScript 核心库的定义文件中已经定义好了,比如IArguments,NodeList,HTMLCollection等。

function sum() {
    let args: {
        [index: number]: number;
        length: number;
        callee: Function;
    } = arguments;
}

除了定义了索引的类型是数字,值的类型也必须是数字之外,也定义了它还有 length 和 callee 两个属性。

function sum() {
    let args: IArguments = arguments;
}
其中 IArgumentsTypeScript 中定义好了的类型,它实际上就是:
interface IArguments {
    [index: number]: any;
    length: number;
    callee: Function;
}