原始类型
Javascript原始类型也同样适用于 TypeScript的类型系统。因此,string, number,boolean也可以被用作类型注解:
let num: number;
let str: string;
let bool: boolean;
num = 123;
num = 123.45;
num = '123'; //Type '"123"' is not assignable to type 'number'
str = '123';
str = 123; //Type '123' is not assignable to type 'string'
bool = true;
bool = false;
bool = 'false';//Type '"false"' is not assignable to type 'boolean'.
数组
类型注解+[]
,它能让你安全的使用任何有关数组的操作,而且它能放置一些类似赋值错误类型给成员的行为。
// 元素类型加[]写法
let list:number[] = [1,2,3]
// 数组泛型写法
let list: Array<number> = [1,2,3]
元祖
已知元素数量和类型的数组
// 声明一个元组类型
let x: [string, number];
// 初始化赋值
x = ['hello', 10]; // OK
// 初始化错误
x = [10, 'hello']; // Error
枚举
在计算机语言中一般用数值来表示某种状态,这种方式不直观,可读性很差。枚举就是把给一些计算机的状态(数字)和一个自然语言相应含义的单词对应起来,目的是把所有的情况都用枚举写出来,这样根据不同的状态对应不同的枚举值,提高了代码的可读性。
枚举类型可以为一组数值赋予友好的名字。默认情况下,从0开始为元素编号,你也可以手动的指定成员的编号。
enum Color {Red = 1,Geeen = 2, Blue = 4}
let c: Color = Color.Green
编译后
var Color;
(function (Color) {
Color[Color["Red"] = 1] = "Red";
Color[Color["Green"] = 2] = "Green";
Color[Color["Blue"] = 4] = "Blue";
})(Color || (Color = {}));
console.log(Color) // 在函数最后进行打印,返回一个JSON
var c = Color.Green;
枚举的名对应是一个变量,然后判断是否有值,如果没有赋值json,然后在自调用函数里,对对象进行赋值,可以在函数最后进行打印,此时json里的值所有的表达式都有返回值,它的返回值就是等号右边的赋值。
{ '1': 'Red', '2': 'Green', '3': 'Blue', Red: 1, Green: 2, Blue: 3 }
如果你看不大明白上面的代码,那么你必须知道console.log(Color["Red"]=0)
返回0。
此外,枚举类型提供的一个遍历是你可以由枚举的值得到它的名字(从上面编译后的源码就可以看出)。例如,我们知道值为2,但是不确定它映射到Color里的哪个名字,我们可以查找相应的名字:
enum Color {Red = 1, Green, Blue}
let colorName: string = Color[2];
console.log(colorName); // 显示'Green'因为上面代码里它的值是2
null & undefined
null和undefined是其他所有类型的子类型
const n1:null = 123;
const n2:undefined = '123';
如果一个变量的值确实需要是null或者undefined, 可以像下面这么用, ts会自动根据if/else推导出正确类型:
// 这是"联合类型", 在"高级类型"中会有详细介绍, 表示n可能是undefined也可能是number
let num: undefined|number;
if(Math.random()>0.5) num = 1;
if(undefined !== num) {
num++;
}
any
any类型在 TypeScript 类型系统中占有特殊的地位。它提供给你一个类型系统的【后门】,TypeScript将会把类型检查关闭。在类型系统里any能够兼容所有的类型(包括它自己)。因此,所有的类型都能够被赋值给它。它也能被赋值给其他任何类型。
void
使用 :void
来表示一个函数没有返回值
function log(message:string):void{
console.log(message)
}
声明一个void类型的变量没有什么大用,因为你只能为它赋予undefined和null:
let unusable:void = undefined
never
never表示不可达, 用文字还真不好描述, 主要使用在throw的情况下:
function error():never{
throw '错了!';
}
进阶
interface
订立接口有助于我们对对象内的值进行更好的进行类型标注。但是接口只能规范属性和值的类型。另外,接口中定义的属性就是必须存在的属性。当然,你也可以在属性后面紧跟可选符号?
,来表示某个属性是非必须的。
如果我们用对象的格式存储出行需要的装备,那么可以定义Trip的类型为:
interface Trip {
bag: number;
kettle: number;
map: boolean;
compass: boolean;
destination: string;
magazine?: boolean;
biscuit: boolean;
}
function checkEquipment(ready: Trip): void {
let ct: string[] = []
for (let i in ready) {
ct.push(i)
}
console.log(`这次出行,我们带上的装备有: ${ct.join('、')}`)
}
const ready = {bag: 3,kettle: 3,map: true, compass: true,destination: 'AMAZON',biscuit: true}
checkEquipment(ready)
在这种情况下,当我们给ready赋值的时候, 如果任何一个字段没有被赋值或者字段对应的数据类型不对, ts都会提示错误, 这样就保证了我们写代码不会出现上述的小错误。
可选选项(?)
上面的例子中,出门远行不一定要带magazine,该字段可以不用传值。但是不传的化又会报错!这时候就需要标记magazine字段为可选选项。同样,函数的参数也可以是可选的。
只读属性(readonly)
接口的只读属性可以在前面添加readonly
关键字,来指定这个属性在初始化后就无法被改变,否则报错,如下
// 只读属性
interface Point {
readonly x: number;
readonly y: number;
}
let p1: Point = {x: 5, y: 10}
p1.x = 10
// Cannot assign to 'x' because it is a read-only property.ts(2540)
此外,ts默认有ReadonlyArray<T>
类型,确保数组被创建后无法被任何方法和途径修改,甚至包括把它赋值给一个普通数组。如果要赋值给另一个数组,必须使用as类型断言。
let a: number[] = [1, 2, 3, 4];
let ro: ReadonlyArray<number> = a;
ro[0] = 12; // error!
ro.push(5); // error!
ro.length = 100; // error!
a = ro; // error!
// 使用断言
a = ro as number[];