@TOC
前言
本篇文章将深入去讲解TypeScript
中的常用类型,这也许会是你看过的最全面最细致的TypeScript
教程,点赞关注收藏不迷路🚀🚀🚀!
1、基元类型
JavaScript
有三个非常常用的类型: string
, number
,和boolean
。
它们在 TypeScript
中都有对应的类型,并且这些名称与在 JavaScript
应用typeof
返回的类型的名称相同:
string
表示字符串值,如"Hello, world"
number
表示数字值,如 42 。JavaScript
没有一个特殊的整数运行时值,所以没有等价于int
或float
类型, 一切都只是number
boolean
只有两个值true
和false
类型名称String
, Number
, 和Boolean
(以大写字母开头)是合法的,但指的是一些很少出现在
代码中的特殊内置类型。对于类型,始终使用string
, number
, 或boolean
。
在TypeScript
中,当你使用const
, var
, 或let
时可以直接在变量后加上==类型注释==: type
就可以显式指定变量的类型为type
:
var str: string = "hello,world";
const num: number = 42;
let boo: boolean = true;
但是,在大多数情况下,这不是必需的。只要有可能,TypeScript
就会尝试自动推断代码中的类型。例如,变量的类型是根据其初始化器的类型推断出来的:
// 不需要类型定义--“myName”自动推断为类型“string”
let myName = "AiLjx";
对于已经声明类型的变量,对其赋值时只能赋予其相同类型的数据,否者TypeScript
将会抛出错误:
2、数组
指定数组的类型可以使用ItemType[]
或者Array<ItemType>
,ItemType
指数组元素的类型,
Array<ItemType>
声明类型的方式使用了TypeScript
的泛型语法,对于泛型,之后我会出单独的一篇博文对其详细的介绍
const arr1:number[]=[1,2,3]
const arr2:string[]=['1','2','3']
同样的,对已经指定类型的数组赋不同类型的值,或向其添加不同类型的数据时,TypeScript将会抛出错误:
3、any
TypeScript
还有一个特殊类型 any
,当你不希望某个特定值导致类型检查错误时,可以使用它。
当一个值的类型是any
时,可以访问它的任何属性,将它分配给任何类型的值,或者几乎任何其他语法上的东西都合法的:
src/01-type.ts
:
let obj: any = { x: 0 };
// 以下代码行都不会抛出编译器错误。
// 使用'any'将禁用所有进一步的类型检查
obj.foo();
obj();
obj.bar = 100;
obj = "hello";
const n: number = obj;
但在运行环境下执行代码可能是错误的:
在项目根目录下( tsconfig.json
所在路径)通过运行tsc --watch
(此命令执行一次后会持续监听入口目录下的文件,其发生变化时会自动重新编译)由typescript
包编译src
目录下的文件,编译后的文件就在dist
目录下(前提是 tsconfig.json
中配置了"outDir": "./dist"
):
进入到 dist
目录中,在 node
环境里运行代码,果然报错了。
当你不想写出长类型只是为了让 TypeScript
相信特定的代码行没问题时, any
类型很有用。
但万万不可大量使用any
类型,因为any
没有进行类型检查,使用它就相当于在使用原生JS
,失去了TS
的意义!!!
4、函数
TypeScript
允许您指定函数的输入和输出值的类型。
- 参数类型注释
声明函数时,可以在每个参数后添加类型注解,以声明函数接受的参数类型。参数类型注释位于参数名称之后:
// 参数类型定义
function getName(name: string) {
console.log("Hello, " + name);
}
这里指定了getName
函数接收一个string
类型的参数,当参数类型不匹配时将抛出错误:
即使您的参数上没有类型注释,TypeScript
仍会检查您是否传递了正确数量的参数!
- 返回类型注释
返回类型注释出现在参数列表之后,其指定了函数返回值的类型:
function getName(name: string): string {
console.log("Hello, " + name);
return "Hello, " + name;
}
这里对getName
函数指定了其返回值是string
类型,当函数无返回值或返回值不是string
类型时将抛出错误:
与变量类型注释非常相似,通常不需要返回类型注释,因为 TypeScript
会根据其return
语句推断函数的返回类型。上面例子中的类型注释不会改变任何东西。某些代码库会出于文档目的明确指定返回类型,以防止意外更改或仅出于个人偏好。
- 匿名函数
匿名函数与函数声明有点不同。当一个函数出现在 TypeScript
可以确定它将如何被调用的地方时,该函数的参数会自动指定类型。
即使参数s
没有类型注释,TypeScript
也会使用forEach
函数的类型,以及数组的推断类型来确定s
的类型。这个过程称为上下文类型,因为函数发生在其中的上下文通知它应该具有什么类型。
与推理规则类似,你不需要明确了解这是如何发生的,但了解它的机制确实可以帮助你注意何时不需要类型注释。
从这里我们就能看出TypeScript
的强大之处,它不仅能够自动推断类型并发现错误,还能提示你错误的地方,以及修复建议,配合VS code
编译器还能实现快速修复:
5、对象
除了string
, number
, boolean
类型(又称基元类型)外,你将遇到的最常见的类型是对象类型。
这指的是任何带有属性的 JavaScript
值,几乎是所有属性!要定义对象类型,我们只需列出其属性及其类型。
let obj: { x: number; y: number } = { x: 1, y: 2 };
对于指定类型的对象其值不符合指定的类型时抛出错误:
- 可选属性
在指定的类型属性名后加上一个?
,可以指定该属性为可选属性:
let obj2: { x?: number; y: number } = {
y: 2, // x 是可选属性,对象内不含x属性时将不再抛出错误
};
不能直接对可选属性进行操作,不然就会抛出错误:
这很好理解,因为可选属性没有限制用户必传,如果访问一个不存在的属性,将获得值undefined
,此时对其操作TypeScript
就会抛出错误提醒你。
正确的做法:
function ObjFn(obj: { x?: number; y: number }) {
console.log(obj.y++);
if (obj.x) { // 先判断可选属性是否存在
console.log(obj.x++);
}
}
6、unknown
与 any
类型类似,可以设置任何的类型值,随后可以更改类型,但unknown
要比any
更加安全,看个例子:
let a: any = "Ailjx";
a = [];
a.push("0");
上面代码在编译与运行时都是正常的,但是当我们手误写错了push
方法后你就会发现问题所在:
let a: any = "Ailjx";
a = [];
a.psh("0");
这段代码在编译时不会报错,只会在运行时报错,这就失去了TypeScript
在编译时检查错误的功能,在项目比较大时,参与的人多时,就很难避免这样类似的问题,因此unknown
类型出现了:
虽然我们将其类型更改为数组类型,但是编译器认为其依旧是unknown
类型,该类型没有push
方法,就会报错,除非我们先判断类型:
let a: unknown = "Ailjx";
a = [];
if (a instanceof Array) {
a.push("0");
}
这样代码就没问题了,这时如果你push方法写错了,编译器就会报错提示你了:
虽然有些麻烦,但是相比 any
类型说,更加安全,在代码编译期间,就能帮我们发现由于类型造成的问题,因此在大多的场景,建议使用 unknown
类型替代 any
。
7、其它类型
void
void
表示不返回值的函数的返回值:
function A() {}
const a = A(); // type A = void
只要函数没有任何return
语句,或者没有从这些返回语句中返回任何显式值,它的推断类型就是void
在JavaScript
中,一个不返回任何值的函数将隐含地返回undefinded
的值,但是,在TypeScript
中,void
和undefined
是不一样的
object
特殊类型 object
指的是任何不是基元的值( string
、number
、bigint
、boolean
、symbol
、null
或 undefined
)(即对象)
这与空对象类型{}
不同,也与全局类型 Object
(大写的O
)不同, Object
类型一般永远也用不上,使用的都是object
let a: object; // a只能接受一个对象
a = {};
a = {
name: "Ailjx",
};
a = function () {};
a = 1; // err:不能将类型“number”分配给类型“object”
请注意,在JavaScript
中,函数值是对象,它们有属性,在它们的原型链中有Object.prototype
,是Object
的实例,你可以对它们调用 Object.key
等等,由于这个原因,函数类型在TypeScript
中被认为是object
!
never
never
类型表示的是那些永不存在的值的类型:
-
可以表示总是抛出异常或根本不会有返回值的函数的返回值类型
function error(msg: string): never { throw new Error(msg); } // 推断出fail返回值类型为never function fail() { return error("Ailjx"); } // A函数会造成死循环,根本不会有返回值,可以用never来表示返回值类型 function A(): never { while (true) {} }
-
被永不为真的类型保护所约束下的变量类型
function Sw(a: boolean) { switch (a) { case true: return a; case false: return a; default: // 这个分支永远不可能到达 // 此时 _a类型为 never const _a = a; return _a; } }
never
类型可以分配给每个类型,但是,没有任何类型可以分配给never
(除了never
本身)
never
类型在实际开发中几乎是使用不到,最大的用处可能就是用来表达一个总是抛出异常的函数的返回值类型了
Function
全局类型Function
描述了 JavaScript
中所有函数值上的属性,如bind
、call
、apply
和其他属性,即 Function
类型的值可以被任何函数赋值,并且总是可以被调用(不会受参数的限制),这些调用返回的都是 any
类型
let fn: Function;
fn = () => {};
fn = function () {};
fn = function (a: number): number {
return a;
};
// 虽然fn的值是一个必须接受一个number类型参数的函数
// 但因为fn类型为Function,调用fn时可以不传参数
fn();
fn('1',2,true) // 还可以随便传参
const a = fn(1); // a的类型依旧为any
从上面调用fn
的例子可以知道这并不安全,一般来说最好避免,因为 any
返回类型都不安全,并且也失去了参数的类型限制
一般情况下,想表示一个函数几乎不会使用Function
,而是使用函数类型
结语
至此,本篇文章内容就全部结束了,如果本篇文章对你有所帮助,还请客官一件四连!
参考资料:TypeScript官网