# 基本类型
## 基本数据类型
ts 支持与 js 几乎相同的数据类型,但是增加对数据类型的限制
``` let isDone: boolean = false; let name: string = "chen"; let list: number[] = [1, 2, 3]; let sentence: string = `Hello, my name is ${name}`; let str = "abc"; str = 123; // 类型不可以转换的错误 ```
## 元组
新增元组类型来解决一个数组中包含不同类型的情况
``` let x: [string, number]; x = ['hello', 10]; ```
## 枚举
新增枚举类型,可以使用枚举类型对一组数组赋予别名
``` enum Color{Red, Green, Blue} let c: Color = Color.Green; ```
默认情况下,枚举类型从0开始元素编号,支持手动指定成员的数值
``` enum Color{Red = 1, Green, Blue}; let c: Color = Color.Green; ```
枚举类型支持通过枚举的值来得到对应的名字
``` enum Color{Red = 1, Green, Blue}; console.log(Color[2]); // Green ```
## Any
不能判断一个变量的具体类型时候,可以使用 Any , 效果将会与 js 中相似,支持不同数据类型之间的赋值
``` let notSure: any = 4; notSure = 'maybe a string indeed'; ```
这个类型同样对数组有效
``` let list: any[] = [1, true, "free"]; list[1] = 100; ```
## Void
void 类型一般用于声明函数没有返回值
``` function warnUser(): void{ console.log("This is my warning message"); } ```
声明一个void类型的变量没有什么大用,因为你只能为它赋予 undefined 和 null
``` let unusable: void = undefined; ```
## null和undefined
和js中的 null 和 undefined 相似,但当在 tsconfig.js 文件中设置 strictNullChecks 为 true 时,就不能将 null 和 undefined 赋值给除它们自身和 void之外的任意类型
## never
never 类型表示的是那些永不存在的值的类型,例如抛出异常或者死循环的函数,或者是永不为真的变量,never 类型可以是任何类型的子类型,也可以赋值给任何类型
``` // 抛出错误的函数 function error(message: string): never{ throw new Error(message); } // 死循环的函数 function infiniteLoop(): never{ while(true){ } } ```
## Object
和 js 中相似
## 类型断言
可以理解成其他语言中的强转,typescript将不再进行特殊的数据检查和解构,它没有运行时的影响,只是在编译阶段起作用
类型断言有两种形式写法,其一是"尖括号"语法:
``` let someValue: any = "this is a string"; let strLength: number = (<string>someValue).length; ```
另一个为as语法:
``` let someValue: any = "this is a string"; let strLength: number = (someValue as string).length; ```
# 变量声明
因为typescript是javascript的超集,所以它本身就支持let和const,其中变量声明的方式也和js相似,这里不作进一步说明
# 接口
typescript的核心原则之一是对值所具有的结构进行类型检查。在typescript里,接口的作用就是为这些类型命名和为你的代码或第三方代码定义契约
## 接口初探
接口可以用作规范函数中一些必须的参数,如下两个例子,效果是等价的
``` function printLabel(labelledObj: {label: string}) { console.log(labelledObj.label); } ``` ``` interface LabelledValue { label: string; } function printLabel(labelledObj: LabelledValue) { console.log(labelledObj.label); } ```
## 可选属性
接口里的属性不全是必需的,带有可选属性的接口与普通的接口定义区别在于在可选属性名字定义的后面加一个?符号
``` interface SquareConfig{ color?: string; width?: number; } ```
## 只读属性
一些对象属性只能在对象刚刚创建的时候修改其值,你可以在属性名前用readonly来指定只读属性:
``` interface Point { readonly x: number; readonly y: number; } let p1: Point = {x: 10, y: 20}; p1.x = 5; // error! ```
## readonly 和 const
最简单判断该用readonly还是const的方法是看要把它作为变量使用还是作为一个属性,作为变量使用的话用const,作为属性则使用readonly
## 额外的属性检查
如果需要有除定义的函数变量之外的场景,可以添加一个字符串索引签名
``` interface SquareConfig { color?: string; width?: number; [propName: string]: any; // 字符串索引签名 } ```
如果不加字符串索引签名,不可以定义除color, width以外的属性
## 函数类型
除了描述带有属性的普通对象外,接口也可以描述函数类型
``` interface SearchFunc { (source: string, subString: string): boolean; // 确定函数的返回值类型为boolean类型 } let mySearch: SearchFunc; mySearch = function(source: string, subString: string) { let result = source.search(subString); return result > -1; } ```
## 可索引的类型
接口支持描述那些能够“通过索引得到”的类型,比如a[10]
``` interface StringArray { [index: number]: string; } ```
typescript支持number和string两种索引签名,有个问题要注意,number类型的索引返回值需是返回值类型的子类型,因为number索引时,js会将它先转换成string再去索引,有可能出现与string索引重复的情况
``` class Animal{ name: string; } class Dog extends Animal { breed: string; } // 错误:使用数值型的字符串索引,有时会得到完全不同的Animal interface NotOkay { [x: number]: Animal; [x: string]: Dog; } ```
## 类类型
接口可以明确强制一个类去符合某种契约(比如变量或者函数)
``` interface ClockInterface{ currentTime: Date; setTime(d: Date); } class Clock implements ClockInterface{ currentTime: Date; setTime(d: Date) { this.currentTime = d; } constructor(h: number, m: number) {} } ```
## 继承接口
继承的接口可以把一个接口里的成员复制到另一个接口里,可以更灵活地将接口分割到可重用的模块里
``` interface Shape{ color: string; } interface Square extends Shape { sideLength: number; } let square = <Square>(); square.color = 'blue'; square.sideLength = 10; ```
一个接口可以继承多个接口,创建出多个接口的合成接口
``` interface Shape{ color: string; } interface PenStroke{ penWidth: number; } interface Square extends Shape, PenStroke { sideLength: number; } ```
# 类
typescript中的类和ES6中的比较相似,这里介绍一些它们之间不同的地方
## 共有修饰符
在typescrip中,成员都默认为public,当然也可以明确的将一个成员标记为public
## 私有修饰符
当成员被标记成private时,它就不能在声明它的类的外部访问
## 受保护修饰符
protected修饰符与private修饰符的行为很相似,但有一点不同,protected成员在派生类中仍然可以访问
``` class Person { protected name: string; constructor(name: string) { this.name = name; } } class Employee extends Person { private department: string; constructor(name: string, department: string) { super(name); this.department = department; } } let howard = new Employee('Howard', 'Sales'); console.log(howard.name); // 错误,类外不能引用 ```
## readonly属性
可以使用readonly关键字将属性设置为只读的,只读属性必需在声明时或构造函数里被初始化
## 存取器
typescript支持通过getters/setters来截取对象对象成员的访问。
``` class Employee { private _fullName: string; get fullName(): string { return this._fullName; } set fullName(newName: string) { if(passcode && passcode == "secret passcode") { this._fullName = newName; }else { console.log("Error: Unauthorized update of employee!"); } } }