typescript:原始类型与对象类型

一、原始类型的类型标注

(1)除了最常见的 number / string / boolean / null / undefined, ECMAScript 2015(ES6)、2020 (ES11) 又分别引入了 2 个新的原始类型:symbol 与 bigint 。在 TypeScript 中它们都有对应的类型注解。

const name: string = 'linbudu';
const age: number = 24;
const male: boolean = false;
const undef: undefined = undefined;
const nul: null = null;
const obj: object = { name, age, male };
const bigintVar1: bigint = 9007199254740991n;
const bigintVar2: bigint = BigInt(9007199254740991);
const symbolVar: symbol = Symbol('unique');

(2) null 与 undefined

const tmp1: null = null;
const tmp2: undefined = undefined;

const tmp3: string = null; // 仅在关闭 strictNullChecks 时成立,下同
const tmp4: string = undefined;

1、在 JavaScript 中,null 与 undefined 分别表示“这里有值,但是个空值”和“这里没有值”。

2、而在 TypeScript 中,null 与 undefined 类型都是有具体意义的类型。也就是说,它们作为类型时,表示的是一个有意义的具体类型值。这两者在没有开启 strictNullChecks 检查的情况下,会被视作其他类型的子类型,比如 string 类型会被认为包含了 null 与 undefined 类型

(3)void

const voidVar1: void = undefined;

const voidVar2: void = null; // 需要关闭 strictNullChecks

1、TypeScript 的原始类型标注中也有 void,但与 JavaScript 中不同的是,这里的 void 用于描述一个内部没有 return 语句,或者没有显式 return 一个值的函数的返回值。

2、null 与 undefined可以赋值给void类型的变量。

二、数组类型标注

const arr1: string[] = [];

const arr2: Array<string> = [];

 (1)元组(Tuple)

const arr4: [string, string, string] = ['lin', 'bu', 'du'];

console.log(arr4[599]);

 1、在某些情况下,使用 元组(Tuple) 来代替数组要更加妥当,比如一个数组中只存放固定长度的变量,但我们进行了超出长度地访问。

2、支持在某一个位置上的可选成员。对于标记为可选的成员,在 --strictNullCheckes 配置下会被视为一个 string | undefined 的类型。

3、TypeScript 4.0 中,有了具名元组(Labeled Tuple Elements)的支持。

4、使用元组确实能帮助我们进一步提升数组结构的严谨性,包括基于位置的类型标注、避免出现越界访问等等。

5、数组与元组只读的修饰

  • 你只能将整个数组/元组标记为只读,而不能像对象那样标记某个属性为只读。

  • 一旦被标记为只读,那这个只读数组/元组的类型上,将不再具有 push、pop 等方法(即会修改原数组的方法),因此报错信息也将是类型 xxx 上不存在属性“push”这种。这一实现的本质是只读数组与只读元组的类型实际上变成了 ReadonlyArray,而不再是 Array。

三、对象的类型标注

interface IDescription {
  name: string;
  age: number;
  male: boolean;
}

const obj1: IDescription = {
  name: 'linbudu',
  age: 599,
  male: true,
};
  • 每一个属性的值必须一一对应到接口的属性类型

  • 不能有多的属性,也不能有少的属性,包括直接在对象内部声明,或是 obj1.other = 'xxx' 这样属性访问赋值的形式

(1)修饰接口属性

1、可选:?

interface IDescription {
  name: string;
  age: number;
  male?: boolean;
  func?: Function;
}

2、只读:readonly(作用:防止对象的属性被再次赋值)

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

四、type 与 interface

 (1)interface 用来描述对象、类的结构,而类型别名用来将一个函数签名、一组联合类型、一个工具类型等等抽离成一个完整独立的类型

(2)大部分场景下接口结构都可以被类型别名所取代,因此,只要你觉得统一使用类型别名让你觉得更整齐,也没什么问题

五、object、Object 以及 { }

 (1)Object

1、原型链的顶端是 Object 以及 Function,这也就意味着所有的原始类型与对象类型最终都指向 Object,在 TypeScript 中就表现为 Object 包含了所有的类型。

// 对于 undefined、null、void 0 ,需要关闭 strictNullChecks
const tmp1: Object = undefined;
const tmp2: Object = null;
const tmp3: Object = void 0;

const tmp4: Object = 'linbudu';
const tmp5: Object = 599;
const tmp6: Object = { name: 'linbudu' };
const tmp7: Object = () => {};
const tmp8: Object = [];

2、和 Object 类似的还有 Boolean、Number、String、Symbol,这几个装箱类型(Boxed Types) 同样包含了一些超出预期的类型。以 String 为例,它同样包括 undefined、null、void,以及代表的 拆箱类型(Unboxed Types) string,但并不包括其他装箱类型对应的拆箱类型,如 boolean 与 基本对象类型

const tmp9: String = undefined;
const tmp10: String = null;
const tmp11: String = void 0;
const tmp12: String = 'linbudu';

// 以下不成立,因为不是字符串类型的拆箱类型
const tmp13: String = 599; // X
const tmp14: String = { name: 'linbudu' }; // X
const tmp15: String = () => {}; // X
const tmp16: String = []; // X

3、在任何情况下,你都不应该使用这些装箱类型。

(2)object

1、object 的引入就是为了解决对 Object 类型的错误使用,它代表所有非原始类型的类型,即数组、对象与函数类型这些

const tmp17: object = undefined;
const tmp18: object = null;
const tmp19: object = void 0;

const tmp20: object = 'linbudu';  // X 不成立,值为原始类型
const tmp21: object = 599; // X 不成立,值为原始类型

const tmp22: object = { name: 'linbudu' };
const tmp23: object = () => {};
const tmp24: object = [];

(3){}

1、可以认为{}就是一个对象字面量类型(对应到字符串字面量类型这样)。否则,可以认为使用{}作为类型签名就是一个合法的,但内部无属性定义的空对象,这类似于 Object(想想 new Object()),它意味着任何非 null / undefined 的值。


const tmp25: {} = undefined; // 仅在关闭 strictNullChecks 时成立,下同
const tmp26: {} = null;
const tmp27: {} = void 0; // void 0 等价于 undefined

const tmp28: {} = 'linbudu';
const tmp29: {} = 599;
const tmp30: {} = { name: 'linbudu' };
const tmp31: {} = () => {};
const tmp32: {} = [];

 2、虽然能够将其作为变量的类型,但你实际上无法对这个变量进行任何赋值操作

const tmp30: {} = { name: 'linbudu' };

tmp30.age = 18; // X 类型“{}”上不存在属性“age”。

(4)总结

  • 在任何时候都不要,不要,不要使用 Object 以及类似的装箱类型。

  • 当你不确定某个变量的具体类型,但能确定它不是原始类型,可以使用 object。但我更推荐进一步区分,也就是使用 Record<string, unknown> 或 Record<string, any> 表示对象,unknown[] 或 any[] 表示数组,(...args: any[]) => any表示函数这样。

  • 我们同样要避免使用{}{}意味着任何非 null / undefined 的值,从这个层面上看,使用它和使用 any 一样恶劣。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值