Typescript部分知识点

news/2024/10/31 5:31:04/

布尔值是最基础的数据类型,在 TypeScript 中,使用 boolean 定义布尔值类型:

let isDone: boolean = false;// 编译通过
// 后面约定,未强调编译错误的代码片段,默认为编译通过

注意:使用构造函数 Boolean 创造的对象不是布尔值:

let createdByNewBoolean: boolean = new Boolean(1);// Type 'Boolean' is not assignable to type 'boolean'.
//   'boolean' is a primitive, but 'Boolean' is a wrapper object. Prefer using 'boolean' when possible.

事实上 new Boolean() 返回的是一个 Boolean 对象:

let createdByNewBoolean: Boolean = new Boolean(1);

直接调用 Boolean 也可以返回一个 boolean 类型:

let createdByBoolean: boolean = Boolean(1);

有时候我们希望一个接口允许有任意的属性,可以使用如下方式:

interface Person {name: string;age?: number;[propName: string]: any;
}let tom: Person = {name: 'Tom',gender: 'male'
};

使用 [propName: string] 定义了任意属性取 string 类型的值。

需要注意的是,一旦定义了任意属性,那么确定属性和可选属性的类型都必须是它的类型的子集

interface Person {name: string;age?: number;[propName: string]: string;
}let tom: Person = {name: 'Tom',age: 25,gender: 'male'
};// index.ts(3,5): error TS2411: Property 'age' of type 'number' is not assignable to string index type 'string'.
// index.ts(7,5): error TS2322: Type '{ [x: string]: string | number; name: string; age: number; gender: string; }' is not assignable to type 'Person'.
//   Index signatures are incompatible.
//     Type 'string | number' is not assignable to type 'string'.
//       Type 'number' is not assignable to type 'string'.

上例中,任意属性的值允许是 string,但是可选属性 age 的值却是 numbernumber 不是 string 的子属性,所以报错了。

另外,在报错信息中可以看出,此时 { name: 'Tom', age: 25, gender: 'male' } 的类型被推断成了 { [x: string]: string | number; name: string; age: number; gender: string; },这是联合类型和接口的结合。

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

interface Person {name: string;age?: number;[propName: string]: string | number;
}let tom: Person = {name: 'Tom',age: 25,gender: 'male'
};

只读属性§

有时候我们希望对象中的一些字段只能在创建的时候被赋值,那么可以用 readonly 定义只读属性:

interface Person {readonly id: number;name: string;age?: number;[propName: string]: any;
}let tom: Person = {id: 89757,name: 'Tom',gender: 'male'
};tom.id = 9527;// index.ts(14,5): error TS2540: Cannot assign to 'id' because it is a constant or a read-only property.

上例中,使用 readonly 定义的属性 id 初始化后,又被赋值了,所以报错了。

注意,只读的约束存在于第一次给对象赋值的时候,而不是第一次给只读属性赋值的时候

interface Person {readonly id: number;name: string;age?: number;[propName: string]: any;
}let tom: Person = {name: 'Tom',gender: 'male'
};tom.id = 89757;// index.ts(8,5): error TS2322: Type '{ name: string; gender: string; }' is not assignable to type 'Person'.
//   Property 'id' is missing in type '{ name: string; gender: string; }'.
// index.ts(13,5): error TS2540: Cannot assign to 'id' because it is a constant or a read-only property.

上例中,报错信息有两处,第一处是在对 tom 进行赋值的时候,没有给 id 赋值。

第二处是在给 tom.id 赋值的时候,由于它是只读属性,所以报错了。

类型断言

类型断言(Type Assertion)可以用来手动指定一个值的类型。

语法§

值 as 类型

<类型>值

在 tsx 语法(React 的 jsx 语法的 ts 版)中必须使用前者,即 值 as 类型

形如 <Foo> 的语法在 tsx 中表示的是一个 ReactNode,在 ts 中除了表示类型断言之外,也可能是表示一个泛型。

故建议大家在使用类型断言时,统一使用 值 as 类型 这样的语法,本书中也会贯彻这一思想。

类型断言的用途§

类型断言的常见用途有以下几种:

将一个联合类型断言为其中一个类型§

之前提到过,当 TypeScript 不确定一个联合类型的变量到底是哪个类型的时候,我们只能访问此联合类型的所有类型中共有的属性或方法

interface Cat {name: string;run(): void;
}
interface Fish {name: string;swim(): void;
}function getName(animal: Cat | Fish) {return animal.name;
}

而有时候,我们确实需要在还不确定类型的时候就访问其中一个类型特有的属性或方法,比如:

interface Cat {name: string;run(): void;
}
interface Fish {name: string;swim(): void;
}function isFish(animal: Cat | Fish) {if (typeof animal.swim === 'function') {return true;}return false;
}// index.ts:11:23 - error TS2339: Property 'swim' does not exist on type 'Cat | Fish'.
//   Property 'swim' does not exist on type 'Cat'.

上面的例子中,获取 animal.swim 的时候会报错。

此时可以使用类型断言,将 animal 断言成 Fish

interface Cat {name: string;run(): void;
}
interface Fish {name: string;swim(): void;
}function isFish(animal: Cat | Fish) {if (typeof (animal as Fish).swim === 'function') {return true;}return false;
}

这样就可以解决访问 animal.swim 时报错的问题了。

需要注意的是,类型断言只能够「欺骗」TypeScript 编译器,无法避免运行时的错误,反而滥用类型断言可能会导致运行时错误:

interface Cat {name: string;run(): void;
}
interface Fish {name: string;swim(): void;
}function swim(animal: Cat | Fish) {(animal as Fish).swim();
}const tom: Cat = {name: 'Tom',run() { console.log('run') }
};
swim(tom);
// Uncaught TypeError: animal.swim is not a function`

上面的例子编译时不会报错,但在运行时会报错:

Uncaught TypeError: animal.swim is not a function`

原因是 (animal as Fish).swim() 这段代码隐藏了 animal 可能为 Cat 的情况,将 animal 直接断言为 Fish 了,而 TypeScript 编译器信任了我们的断言,故在调用 swim() 时没有编译错误。

可是 swim 函数接受的参数是 Cat | Fish,一旦传入的参数是 Cat 类型的变量,由于 Cat 上没有 swim 方法,就会导致运行时错误了。

总之,使用类型断言时一定要格外小心,尽量避免断言后调用方法或引用深层属性,以减少不必要的运行时错误。


http://www.ppmy.cn/news/6027.html

相关文章

从零开始TP6配置ThinkPHP-ApiDoc

系统&#xff1a;windows11 集成环境&#xff1a;小皮&#xff08;原phpstudy&#xff09; composer:2.5 准备工作&#xff1a;安装小皮后&#xff0c;在软件管理中安装composer&#xff0c;2.3安装不上去&#xff0c;只能安装1.8.5&#xff0c;没关系安装后升级成为新版就可…

接口(interface) 和 抽象类(abstract class) 的使用区别

接口(interface) 和 抽象类(abstract class) 的使用区别 在实践中&#xff0c;可能不太清楚什么时候使用接口&#xff0c;什么时候使用抽象类。 一个最准确的比喻可能会有所帮助。 可以将 interface 想象为定义“can-do”或“is-a”关系&#xff0c;而abstract class 更应该…

Hive+Spark离线数仓工业项目实战--环境构建(3)

项目环境配置 根据需求实现项目环境配置 实施 - 注意&#xff1a;所有软件Docker、Hadoop、Hive、Spark、Sqoop都已经装好&#xff0c;不需要额外安装配置&#xff0c;启动即可 配置网络&#xff1a;如果你的VM Nat网络不是88网段&#xff0c;请按照以下修改 - 修改Linux虚拟…

【Three.js入门】标准网格材质、置换贴图、粗糙度贴图、金属贴图、法线贴图

个人简介 &#x1f440;个人主页&#xff1a; 前端杂货铺 &#x1f64b;‍♂️学习方向&#xff1a; 主攻前端方向&#xff0c;也会涉及到服务端 &#x1f4c3;个人状态&#xff1a; 在校大学生一枚&#xff0c;已拿多个前端 offer&#xff08;秋招&#xff09; &#x1f680;未…

503.下一个更大元素II,42. 接雨水

503. 下一个更大元素 II 给定一个循环数组 nums &#xff08; nums[nums.length - 1] 的下一个元素是 nums[0] &#xff09;&#xff0c;返回 nums 中每个元素的 下一个更大元素 。 数字 x 的 下一个更大的元素 是按数组遍历顺序&#xff0c;这个数字之后的第一个比它更大的数…

C语言--操作符

文章目录一、数据的存储二、算术操作符三、移位操作符左移位操作符<<右移操作符四、位操作符五、赋值操作符六、单目操作符sizeof前后置七、关系操作符一、数据的存储 如果想要准确的掌握每个操作符的作用&#xff0c;那么首先需要理解数据在计算机中的存储和运算规则。…

JMeter+Ant+Jenkins接口自动化测试框架

一:简介 大致思路&#xff1a;Jmeter可以做接口测试&#xff0c;也能做压力测试&#xff0c;而且是开源软件&#xff1b;Ant是基于Java的构建工具&#xff0c;完成脚本执行并收集结果生成报告&#xff0c;可以跨平台&#xff0c;Jenkins是持续集成工具。将这三者结合起来可以搭…

扫雷游戏的设计(百分百还原电脑操作)

目录 &#x1f332;了解扫雷游戏的作用原理并梳理思路 &#x1f332;扫雷游戏前期部分完善 &#x1f337;文件的创建 &#x1f337;创建菜单&#xff0c;完善主函数 &#x1f333;代码呈现&#xff1a; &#x1f332;扫雷游戏主题内容 &#x1f334;第一步初始化棋盘 &#x1…