2024/10/20: TypeScript 学习笔记三:TypeScript 类型系统
一、TypeScript 提供的对应类型:
- boolean
- string
- number
- bigint
- undefined
- null
- symbol
二、object 类型仅能够赋值给以下三种类型:
- 顶端类型 any 和 unknown
- Object 类型
- 空对象类型字面量“{}”
注:所有类型都是顶端类型的子类型,所以object 能够赋值给顶端类型 any 和 unknown
const nonPrimitive:object = {} const a:any = nonPrimitive const b: unknown = nonPrimitive
Object 类型描述了所有对象都共享的属性和方法,所以很自然地表示对象类型的 object 类型能够赋值给 Object 类型。示例如下:
const nonPrimitive: object = {}
const obj: Object = nonPrimitive
object 类型也能够赋值给空对象类型字面量 “{}”。示例如下:
const nonPrimitive:object = {}
const obj:{} = nonPrimitive
三、定义一个常用的 object 类型的数据
let point:{ readonly x: number; // 只读属性 // 只读属性的值在初始化后不允许再被修改。 y:number; z?: number; // typescript 会自动 定义成 z?: number | undefined // 在严格模式下, null 和 undefined 是区别对待的。不能将 null 赋值给 z // 在 非严格模式下,null 与 undefined 均可以赋值给 可选属性 z 。 } // 正确 point = {x: 0, y: 0} point.x = 1 //编译错误,不允许给 x 赋值,因为它是只读属性
四、空对象类型字面量
空对象字面量表示不带任何属性的对象类型,因此不允许在 “{}” 类型上访问任何自定义属性。示例如下:
const point: {} = {x: 0, y: 0} point.x // 编译错误,属性x 不存在于 类型 {}
在 空对象类型字面量 “{}” 上,允许访问对象公共的属性和方法,也就是 Object 类型上定义的方法和属性。示例如下:
const point: {} = {x: 0, y:0}
point.valueOf();
现在可以发现 空对象类型字面量 “{}” 与 Object 类型十分相似。事实上也是如此。单从行为上来看两者是可以互换使用的。例如,除了 undefined 和 null 值外,其他任何值都可以赋值给 空对象类型字面量 “{}” 和 Object 类型。同时,空对象类型字面量 “{}” 和 Object 类型之间也允许互相赋值。示例如下:
let a: Object = 'hi' let b: {} = ‘hi’ a = b; b = a
两者的区别在于语义上。全局的 Object 类型用于描述对象公共的属性和方法,它相当于一种专用类型,因此程序中不应该将自定义变量、参数 等类型直接声明为 Object 类型。空对象类型字面量 “{}” 强调的是不包含属性的对象类型,同时也可以作为 Object 类型的代理来使用。最后也要注意下:在某些场景中新的 object 类型可能是更加合适的选择。
五、弱类型
弱类型指的是同时满足以下条件的对象类型:
- 对象类型中至少包含一个属性。
- 对象类型中所有属性都是可选属性
- 对象类型中不包含字符串索引签名、数值索引签名、调用签名和构造签名
例如,下例中 config 变量的类型是一个弱类型
let config: { url?: string; async?: boolean; timeout?: number }
六、多余属性
const point: {x: number} = {x: 0, y: 0} // y 是多余属性
多余属性会影响类型间的子类型兼容性以及赋值兼容性,也就是说编译器不允许在一些操作中存在多余属性。
多余属性检查在绝大多数场景中都是合理的。如果确定不想让编译器对代码进行多余属性检查,有多种方法能够实现这个效果。如下
- 使用类型断言,这是推荐方法
类型断言能够对类型进行强制转换。例如,我们可以将对象字面量{x:0,y:0}的类型强制转换为 {x: 0} 类型。
类型断言能够绕过多余属性检查的真正原因是:处于类型断言表达式中的对象字面量将不再是“全新的对象字面量类型”,因此编译器也就不会对其进行多余属性检查。
例如:
// 无编译错误 const p0: {x:number} = {x: 0, y: 0} as {x:number} // 无编译错误 const p1: {x: number} = {x: 0, y: 0} as {a: 0, y: 0}
- 启用 “--suppressExcessPropertyErrors” 编译选项
启用该编译选项能够完全禁用整个 TypeScript 工程的多余属性检查,但同时也将完全失去多余属性检查带来的帮助。
我们可以在 tsconfig.json 配置文件中或命令行上启动该编译选项。例如:
{ “compilerOptions”: { "suppressExcessPropertyErrors": true } }
- 使用 “// @ts-ignore” 注释指令
该注释指令能够禁用针对某一行代码的类型检查
// @ts-ignore const point: {x: number} = {x: 0, y: 0}
- 为目标对象类型添加索引签名
若目标对象类型上存在索引签名,那么目标对象可以接受任何属性,因此也就谈不上多余属性。例如:
const point: { x: number; [prop: string]: number; // 索引签名 } = {x: 0, y: 0}
- 最后一种方法也许不是很好理解。如果我们先将对象字面量赋值给某个变量,然后再将该变量赋值给目标对象类型,那么也就不会执行多余属性检查。
这种方法能够生效的原理与类型断言类似,那就是令源对象类型不为“全新的对象字面量类型”,于是编译器将不执行多余属性检查。例如:
const temp = {x: 0, y:0} //无编译错误 const point : {x: number} = temp