基础类型
TypeScript 支持与 JavaScript 几乎相同的数据类型,此外还提供了实用的枚举类型方便我们使用
类型注解:在定义时确定变量类型
const str: string = 'string'
Boolean
布尔值,使用
boolean
表示,值为 true/false
let isDone: boolean = false
Number
数字类型,使用
number
表示,所有数字都是浮点数 支持二进制、八进制、十进制和十六进制字面量
let binaryLiteral: number = 0b10100 // 二进制(0b或0B开头)
let octalLiteral: number = 0o24 // 八进制(ES6规定0o开头,此前为0开头)
let decLiteral: number = 20 // 十进制
let hexLiteral: number = 0x14 // 十六进制(0x或0X开头)
let bigLiteral: bigint = 100n; // BigInt类型(ES6引入,为了与 Number 区分需以 n 为后缀)
String
字符串类型,使用
string
表示,使用双引号("
)或单引号('
)表示字符串
let name: string = 'bob'
name = 'smith'
还可以使用模版字符串,它可以定义多行文本和内嵌表达式。 这种字符串是被反引号包围( `
),并且以 ${ expr }
这种形式嵌入表达式
let name: string = `Yee`
let age: number = 37
let sentence: string = `Hello, my name is ${ name }.
I'll be ${ age + 1 } years old next month.`
这与下面定义 sentence
的方式效果相同:
let sentence: string = 'Hello, my name is ' + name + '.\n\n' +
'I\'ll be ' + (age + 1) + ' years old next month.'
Array
数组类型,两种定义方式如下
- 可以在元素类型后面接上
[]
,表示由此类型元素组成的一个数组
let list1: number[] = [1, 2, 3]
- 使用数组泛型,
Array<元素类型>
let list2: Array<number> = [1, 2, 3]
Tuple
元组类型,表示一个已知元素数量和类型的数组,元组中各个元素的类型不必相同
// 定义一对值分别为 `string` 和 `number` 类型的元组
let x: [string, number]
x = ['hello', 10] // OK
x = [10, 'hello'] // Error
// 当访问一个已知索引的元素,会得到正确的类型
console.log(x[0].substr(1)) // OK
console.log(x[1].substr(1)) // Error, 'number' 不存在 'substr' 方法
// 当访问一个越界的元素会报错
x[3] = "world"; // Error, Property '3' does not exist on type '[string, number]'.
// 可变元组,后面不确定数量及类型的元素
type User = [string, number, string, ...any[]]
const user: User = ['张三', 24, '男', '北京市', '海淀区']
const [username, age, gender, ...rest] = user
console.log('username', username) // username 张三
console.log('age', age) // age 24
console.log('gender', gender) // gender 男
console.log('rest', rest) // rest ['北京市', '海淀区']
Enum
枚举类型,可以为一组数值赋予友好的名字,有默认值并且可自增值,节省编码时间,语义更清晰,可读性更强
enum Color { Red, Green, Blue}
let color: Color = Color.Green
console.log(color) // 1
默认情况下,从 0
开始为元素编号。 也可以手动的指定成员的数值。 例如,将上面的例子改成从 1
开始编号
enum Color { Red = 1, Green, Blue}
let color: Color = Color.Green
console.log(color) // 2
或者,全部都采用手动赋值:
enum Color { Red = 1, Green = 3, Blue = 5 }
let color: Color = Color.Green
console.log(color) // 3
枚举类型提供的一个便利是可以由枚举的值得到它的名字(仅适用于值为0或正整数),越界时返回 undefined
例如,知道数值为 2,但是不确定映射到 Color 里的哪个名字,可以查找相应的名字
enum Color { Red = 1, Green = 3, Blue = 5 }
let colorName1: string = Color[3]
let colorName2: string = Color[6]
console.log(colorName1) // Green
console.log(colorName2) // undefined
当其中一个枚举值为字符串时,则其下一项必须赋初始值,并以此类推
enum Color {
Red = 'red',
Green
}
Unknown
描述一个不知道类型的变量,可以来自动态内容或者想在 API 中接收所有可能类型的值,在这些情况下,想让编译器以及未来的用户知道这个变量可以是任意类型。这个时候会对它使用 unknown 类型
let notSure: unknown = 4
notSure = 'maybe a string instead'
notSure = false
如果有一个 unknwon 类型的变量,可以通过进行 typeof 比较或者更高级的类型检查来将其的类型范围缩小
let maybe: unknown // maybe 可以是字符串、对象、布尔值、未定义或其他类型
const aNumber: number = maybe // Error,unknown 类型不能分配给 number 类型
if (maybe === true) {
const aBoolean: boolean = maybe // 现在 TypeScript 认为 maybe 是一个布尔值
const aString: string = maybe // Error,布尔值不能分配给 string 类型
}
if (typeof maybe === 'string') {
const aString: string = maybe // 现在 TypeScript 认为 maybe 是一个字符串
const aBoolean: boolean = maybe // Error,字符串不能分配给 boolean 类型
}
Any
为那些在编程阶段还不清楚类型的变量指定一个类型。 这些值可能来自于动态的内容,比如来自用户输入或第三方代码库。 这种情况下不希望类型检查器对这些值进行检查而是直接让它们通过编译阶段的检查。 那么可以使用
any
类型来标记这些变量
let notSure: any = 4
notSure = 'maybe a string instead'
notSure = false
在对现有代码进行改写的时候,any类型是十分有用的,它允许在编译时可选择地包含或移除类型检查。 你可能认为 Object 有相似的作用,就像它在其它语言中那样。 但是Object类型的变量只是允许你给它赋任意值 - 但是却不能够在它上面调用任意的方法,即便它真的有这些方法
let notSure: any = 4
notSure.ifItExists() // ifItExists 方法可能在运行时存在
notSure.toFixed() // toFixed方法存在,但编译器不检查
let prettySure: Object = 4
prettySure.toFixed() // Error: 类型 Object 上不存在属性 toFixed
注意:应避免使用 Object
,而是使用非原始 object
类型
当只知道一部分数据的类型时,any类型也是有用的。 比如有一个包含了不同类型数据的数组
let list: any[] = [1, true, 'free']
list[1] = 100
Void
某种程度上来说,
void
类型像是与any
类型相反,它表示没有任何类型。 当一个函数没有返回值时,通常会见到其返回值类型是void
:
function warnUser(): void {
console.log('This is my warning message')
}
声明一个 void
类型的变量没有什么大用,因为你只能为它赋予 undefined
(只在配置文件中 strictNullChecks
未指定时) 和 null
:
let unusable: void = undefined
Null 和 Undefined
undefined
和null
两者各自有自己的类型分别叫做undefined
和null
。 和void
相似,它们的本身的类型用处不是很大
let u: undefined = undefined
let n: null = null
默认情况下 null
和 undefined
是所有类型的子类型。 也就是说可以把 null
和 undefined
赋值给 number
类型的变量
然而,当配置文件中指定了 strictNullChecks
,null
和 undefined
只能赋值给 void
和它们各自,这能避免很多常见的问题
Never
表示的是那些永不存在的值的类型。 例如,
never
类型是那些总是会抛出异常或根本就不会有返回值的函数表达式或箭头函数表达式的返回值类型; 变量也可能是never
类型,当它们被永不为真的类型保护所约束时。
never
类型是任何类型的子类型,也可以赋值给任何类型;然而,没有类型是 never
的子类型或可以赋值给never
类型(除了 never
本身之外)。 即使 any
也不可以赋值给 never
。
下面是一些返回 never
类型的函数:
// 返回 never 的函数必须存在无法达到的终点
function error(message: string): never {
throw new Error(message)
}
function infiniteLoop(): never {
while (true) { }
}
// 推断的返回值类型为 never
function fail() {
return error("Something failed")
}
可以使用 never
避免出现未来扩展新的类没有对应类型的实现,目的是写出类型安全的代码
type dataType = string | number
function neverData(data: dataType) {
if (typeof data === 'string') {
console.log('字符串类型:', data)
} else if (typeof data === 'number') {
console.log('数字类型:', data)
} else {
// 此时这里的 data 被赋予了 never 类型,当上方 dataType 中新增了类型后,这里的 data 被赋予对应的类型
console.log('其他类型:', data)
}
}
Object
表示非原始类型,即除
number
,string
,boolean
,symbol
,null
或undefined
之外的类型
使用 object
类型,就可以更好的表示像 Object.create
这样的 API
。例如:
declare function create(o: object | null): void
create({ prop: 0 }) // OK
create(null) // OK
create(42) // Error
create('string') // Error
create(false) // Error
create(undefined) // Error
::: error
关于 Boolean, Number, String, Symbol 和 Object
一般很容易会认为 Number、 String、 Boolean、Symbol 以及 Object 这些类型和我们以上推荐的小写版本的类型是一样的 但这些类型不属于语言的基本类型,并且几乎在任何时候都不应该被用作一个类型
/**
* Object
* 除了 **`undefined`** 和 **`null`** 之外,其他均可被赋值
* **`{}`** 是 **`Object`** 类型的简写
*/
const data1: Object = 1
const data2: Object = 'a'
const data3: Object = true
const data4: Object = null // 报错
const data5: Object = undefined // 报错
const data6: {} = Symbol()
const data7: {} = {}
any、unknown 区别及应用场景
相同点
任何类型的变量都可以赋值给
any
或unknown
类型
不同点
any
类型的变量可以赋值给除never
之外的其他类型变量,unknown
类型不可以any
类型的变量可以获取 任何属性和方法,但是unkonw
类型不可以
// 不同点 1
type T = { name: string; age: number }
let data: T
function test(a: any, b: unknown) {
data = a // OK
data = b // Error,不能将类型 unknown 分配给类型 T
}
// 不同点 2
function test1(data: any) {
console.log(data.name) // OK
data.printInfo() // OK
}
function test2(data: unknown) {
console.log(data.name) // Error,unknown 不能调用属性
data.printInfo() // Error,unknown 不能调用方法
}
应用场景
any
比较典型的应用场景,1. 自定义守卫,2. 需要进行as any
类型断言的场景
// Vue3 源码片段
// any 的应用场景一—自定义守卫中使用 any
export function isRef(r: any): r is Ref {
return Boolean(r && r.__v_isRef === true) // any 类型的 r 参数在函数内部获取属性
}
unknown
一般用作函数参数,用来接受任意类型的变量实参,但在函数内部只用于再次传递或输出结果,不获取属性的场景
// Vue3 源码 片段 ref 的 unknown 参数
function ref (value ?: unknown) {
return createRef(value) // 函数内部只用于再次传递值,不获取属性
}