# 基本类型与包装对象类型
在 JS 和 TS 中, string
和 String
是有区别的。具体的说一个原始类型,它有字面量和包装对象两种情况。
1 | "hello"; // 字面量 |
所以在对变量进行类型指定的时候也有所区别。
1 | const s1: string = "hello"; // 正确 |
可以看到 string
类型只能被赋予字面量而非包装对象。而 String
既可以被赋予字面量也可以赋予包装对象 \
对于 TS 来说,最好使用小写的类型,因为我们开发在使用这种原始类型的时候,通常都是以字面量进行初始化。并且 TS 中很多内置方法的函数需要接受的参数都定义为小写类型。
1 | const x: number = 1; |
Math.abs()
的参数类型就被定义为小写类型,所以在传入 y
时会发生报错。
# Object 类型与 object 类型
它是一种复合类型。大写的 Object
代表广义对象,除了 null
和 undefined
其他所有类型都能转成对象。在 TS 中,可以用 {}
空对象代指 Object
类型。
1 | const obj: Object = ...; |
而小写的 object
是狭义上的对象,它只能接受字面量对象而不接受那些原始类型。
1 | const obj: object = {foo: 1}; // 正确 |
需要注意的是,小写和大写类型都能调用对象的内置方法如 toString()
, 但是它们不能读取用户自定义的属性方法,如果需要读取用户的自定义属性需要在定义时直接给出属性。
1 | const obj: object = {foo: 1}; |
# undefined 和 null 的特殊性
它们既是值也是类型。并且在它们作为值的时候,所有类型的变量都能被赋值。
1 | const x: number = 1; |
这是为了跟 JS 中的行为保持一致,但是可能会引发潜在的危险,导致 TS 的编译检查不出问题。
1 | const obj: object = undefined; |
需要避免的话在 tsconfig
中打开 strictNullChecks
,这样的话 null
和 undefined
只能被赋予给 any
和 unknown
类型,而且它们之间也不能互相赋值了,保证了一定的安全性。
# 值类型
在 TS 中,单个值也是一种类型。
1 | let x: "hello"; |
上面代码意味着 x 只能被 hello
这个字符串赋值。还有一种写法也能做到上面的效果,那就是 const
定义的变量如果没有被指定类型且被赋值为一个字面量,TS 就会自动推断。
1 | const x = "imtx"; |
TS 推断变量 x
只能被赋予字符串 imtx
,这是很合理的。因为在 JS 中, const
类型定义的变量 x
确实不能再被改变了。但当 x
是对象类型的时候就不会推断了,因为 JS 中, const
定义的对象只是本身不能被改变,但是它内部的属性方法可以被改变。
# 运算符
# keyof 运算符
返回一个对象所有键名组合的联合类型。
1 | type obj = { |
# in 运算符
JS 中的 in
运算符是确定对象是否包含某个属性。而 TS 中的 in
运算符是用于取出联合类型的每一个成员类型。
1 | type U = "a" | "b" | "c"; |
# is 运算符
用于确定一个变量是否属于某个属性。需要注意的是,它不是一个普通的操作符,不能以 A is type
一个表达式来单独写出。而通常放在函数返回类型中,用于类型保护。
1 | const x: number = 1; |
# 类型映射
对于 A 和 B 两个类型,如果它们有很多相同的属性名,但类型不同。那么在定义的时候就略显繁琐。这时候可以结合上面的运算符来进行类型映射。
1 | type A = { |
等价于:
1 | type A = { |
这样做的话,会将所有 B 内的属性名都定义为 boolean 类型,如果需要 A 和 B 的属性名及类型都是相同的,可以使用 [] 运算符做到。
1 | type A = { |
对上面的代码分析如下:
- prop: 存储属性名的代指变量,可以任意取名。
- keyof: 取出 A 中所有成员组成的联合类型。
- in: 取出上述联合类型中的每一个成员。
- A [prop]: 使用 prop 取出 A 中属性对应的相应类型赋给 B。
对于类型映射,还有一些进阶用法。
# + -
修饰符
普通映射无法映射属性的可读和可选属性,
+
修饰符:写成+?
或+readonly
,为映射属性添加?
修饰符或readonly
修饰符。–
修饰符:写成-?
或-readonly
,为映射属性移除?
修饰符或readonly
修饰符。
# 键名重映射
在上面我们原封不动的复制了 A 的属性名, TypeScript 4.1
引入键名重映射可以改变名字,用法如下:
1 | type A = { |
# 属性过滤
键名重映射还可以过滤掉某些属性。下面的例子是只保留字符串属性。
1 | type User = { |