初识TypeScript之对象类型 | 青训营笔记

96 阅读3分钟

这是我参与「第四届青训营」笔记创作活动的的第 17 天。

有这么一句老话:在JS中万物皆为对象。

由于TS的静态类型检测机制,在TS中我们通常把对象{}函数function类class统称为对象。

Object、object、{}

注意区分大小写噢!

Object

我们先来看一下 TypeScript 对Object的定义,TS 把 JS 的Object分成了两个接口来定义:

  1. Object 接口 定义了 JS Object 的原型对象Object.prototype上的属性:
interface Object {
    constructor: Function;
    toString(): string;
    toLocaleString(): string;
    valueOf(): Object;
    hasOwnProperty(v: PropertyKey): boolean;
    isPrototypeOf(v: Object): boolean;
    propertyIsEnumerable(v: PropertyKey): boolean;
}
  1. ObjectConstructor 接口 定义了 Object类 自身的属性,如Object.create()
interface ObjectConstructor {
    new(value?: any): Object;
    (): any;
    (value: any): any;
    readonly prototype: Object;
    getPrototypeOf(o: any): any;
    getOwnPropertyNames(o: any): string[];
    create(o: object | null): any;
    defineProperty<T>(o: T, p: PropertyKey, ...): T;
    // ...
}

非严格模式下,所有的原始类型非原始类型都可以赋值给Object类型的变量。

let obj: Object;

obj = 1
obj = []
obj = 'str'
obj = true
obj = { name: 'abc' }

// 严格模型下不行 ↓
obj = undefined
obj = null

object

object 是 TypeScript v2.2 入的一种非基本类型,不能被赋予原始值。

object类型用于表示非原始类型,也就是除numberstringbooleansymbolnullundefined之外的类型。

let obj : object = {}

obj = [] // OK

obj = 1 // Error
obj = true // Error
obj = 'str' // Error

JS中的 WeakMap 要求键必须是对象,TypeScript 在定义 WeakMap 时,使用的正是 object 约束键的类型。

interface WeakMap<K extends object, V> {
    delete(key: K): boolean;
    get(key: K): V | undefined;
    has(key: K): boolean;
    set(key: K, value: V): this;
}

{ } 类型

{}类型描述了一个没有成员的对象。当你试图访问这样一个对象的任意属性时,TypeScript 会产生一个编译时错误。

image.png

但是,还是可以在{}类型的变量上访问Object类型上定义的所有属性和方法。

三者的区别

  1. 类型 Object 包括原始值,即原始类型的值可以赋值给 Object 类型的变量,原始类型的值也可以访问到Object.prototype上的属性。

    let obj: Object = {foo : 'foo'}
    obj = 1
    obj = []
    obj = true
    
    let str: string = 'str'
    str.hasOwnProperty === Object.prototype.hasOwnProperty // true
    
  2. 当对 Object 类型的变量进行赋值时,如果值对象属性名与 Object 接口中的属性冲突,则 TypeScript 编译器会提示相应的错误。而对于 object 类型来说,TypeScript 编译器不会提示任何错误。 image.png

  3. 在处理 object 类型和字符串索引对象类型的赋值操作时,也要特别注意。这是因为{ [key: string]: string } 类型相比 object 类型更加精确。

    let obj1: { [key: string]: string } = {};
    let obj2: object = {};
    
    obj2 = obj1 // OK
    obj1 = obj2 // Type 'object' is not assignable to type '{ [key: string]: string; }'.
    
  4. 在约束对象类型时,我们应当使用object

  5. Object 是对 TypeScript 对JavaScript Object.prototype原型对象的定义,是所属对象类型的顶层类型,即所有对象类型都继承了Object中定义的属性和方法。同时,由于JavaScript的拆箱装箱机制,Object类型的变量可以被赋予原始值,而基本类型也可以访问Object中定义的属性和方法。

  6. {} 是一个没有任何成员的对象类型,它可以访问Object中定义的属性和方法,也可以被赋予原始值。

函数

函数声明

function add(x: number, y: number): number{
    return x + y;
}

函数表达式

const add = function (x: number, y: number): number{
    return x + y;
}

可选参数

function add(x: number, y?: number): number{
    return y ? x + y : x;
}

默认参数

function add(x: number, y: number = 0): number{
    return x + y;
}

剩余参数

function add(...numbers: number[]): number{
    let sum: number = 0;
    sum = numbers.reduce((total, item)=>{ return total += item }, 0)
}

接口定义函数

interface Add {
    (x: number, y: number): number;
}

class 类

基础语法

class Person {
    name: string
    age: number
    
    constructor(name: string, age: number){
        this.name = name;
        this.age = age;
    }
    
    Hello(): void{
        console.log('hello')
    }
}

let p: Person = new Person('dj', 20)

上面这段代码声明了一个Person类,这个类有两个属性nameage,一个构造函数constructor,和一个Hello方法。最后一行,我们使用new构造了一个Person类的实例对象p