Object Types
在函数声明时,可以指定传入 object 的类型
Copy function foo (obj: { x: number, y: number }){
...
}
指定其中某些参数是 optional
的
Copy function foo (obj: { x: number, y?: number }){
...
}
// both ok
foo({x: 1, y: 1})
foo({x: 1})
不过,如果某一参数是 optional
的,那么就应该在函数体内部对它进行判空
Copy function foo (obj: { x: number, y?: number }){
if(obj.y !== undefined){
...
}
}
Union Types
可以由多个现有的 type 构建新的 type
Copy function foo(id: number | string) {...}
foo(1) // allowed
foo(true) // not allowed
foo接受的 id 就是一个 union type
,他可以是一个 number 或者 string
与上面的 optional
类似,如果在函数中定义了一个参数为 unino type
,那么在函数体内可能需要 narrowing
Copy function foo(id: number | string) {
// not allowed,因为 id 可能是 number,number 没有 toUpperCase() 属性
id.toUpperCase()
// narrowing,allowed
if(typeof id === 'string')
id.toUpperCase()
}
type 关键字
类似于其他语言的 typedefine
,可以将上述的 Object Types、Union Types 定义成一个新的”类型“
Copy type Point = {
x: number,
y: number
}
type ID = number | string
// useage
function foo(point: Point)
function foo(id: ID)
注意的是,type 定义的新类型其实就是一个“别名” (type aliases)
如 type NewString = string,本质上 NewString 就是 string 类型,它们不是两个不同的类型
interface 关键字
interfaces
关键字是另一种给 Object Types 定义”类型“的方式
Copy interface Point = {
x: number,
y: number
}
type aliases 和 interface 的区别
两者在大部分情况下没有区别,可以随意选择使用。
在多数情况下,可以按照自己的偏好选择 type 或者 interface,不过有一个不错的策略是:
尽量使用 interface,除非必须使用 type 的时候
关键的区别就是:interfaces
是可以以增加新的属性的
Copy interface Animal {
name: string
}
// interface 创建后可以继续添加属性
interface Animal {
age: number
}
const cat: Animal
cat.name = 'xxx'
cat.age = 1
Copy type Animal = {
name: string
}
// type 创建后就不能修改
type Aniaml = {
age: number
}
interface 增加属性
Copy interface Animal {
name: string
}
interface Bear extends Animal {
honey: boolean
}
const bear = getBear()
bear.name
bear.honey
type 增加属性
Copy type Animal = {
name: string
}
type Bear = Animal & {
honey: boolean
}
const bear = getBear();
bear.name;
bear.honey;
type 断言
有时候,你能确定一个值的类型,那么就可以使用断言,例如你确定 id 为 'main_canvas' 的 DOM 元素一定是 HTMLCanvasElement 类型
Copy const myCanvas = document.getElementById("main_canvas") as HTMLCanvasElement
另一种用<>
的写法
Copy const myCanvas = <HTMLCanvasElement>document.getElementById("main_canvas")
类型断言在编译后会被移除,所以不必担心会出现 runtime 时问题
断言只能缩小 或者扩大 某一个类型,如下面的例子是不合法的
Copy const foo = 'bar' as number // not allowed
但是上述这一个限制有时候也有点太妨碍了,可以用下面的方法来解决
Copy const foo = (bar as any) as T // 先转为 any 再转为想要的类型
字面量 type
在 Typescript 中,下面两种写法是等价的
Copy const foo = 'bar'
const foo: 'bar' = 'bar'
foo = 'foorbar' // not allowed
不过上面的第二种写法没有太大意义,但是利用union type
,可以限制某一变量的取值范围
Copy const foo: 'foo' | 'bar' = 'bar'
foo = 'foo' // ok
foo = 'foobar' // not ok
union type 不仅仅可以组合相同类型的 type,下面的写法也是可以的
Copy type Foo = 'bar' | number
let foo: Foo = 1 // ok
foo = 'bar' // ok
foo = 'foobar' // not ok
null & undefined
TypeScript 和 JavaScript 一样,也有 null 和 undefined。但是它们的行为取决于 strictNullChecks
flag 是否开启
strictNullChecks off
null 和 undefined 仍然可以被正常访问,也能当做属性赋值给任意值。这和 C# Java 类似,并不做 null checks。
strictNullChecks on
null undefined 是大多数 bug 的来源,因此推荐打开 strictNullChecks
当 strictNullChecks
打开时,需要在访问可能为空的值时,提前判空
! 断言
如果能 100% 保证变量不会为空,可以使用 !
断言,以省去判空逻辑
Copy function foo(x: number){
console.log(x!.toFixed(2))
}
Enums 枚举类型
Enums 分为数字型和字符串型
数字型
Copy // 如果不指定,默认从 0 开始
enum Direction {
Up = 1, Down, Left, Right
}
字符串型
Copy enum Direction {
Up = "UP",
Down = "DOWN",
Left = "LEFT",
Right = "RIGHT"
}
Enums 并不是 TypeScript 对 JavaScript 在**“类型系统层面”**上的扩展,因为 JavaScript 本身并没有枚举类型。如上面的数字型 enum 在 tsc 编译后的 js 文件是这样的:
Copy var Direction;
(function (Direction) {
Direction[Direction["Up"] = 1] = "Up";
Direction[Direction["Down"] = 2] = "Down";
Direction[Direction["Left"] = 3] = "Left";
Direction[Direction["Right"] = 4] = "Right";
})(Direction || (Direction = {}));