和js的基本类型一样,ts都有相对应的类型。除此此外还定义了枚举类型来方便我们的使用。
数字类型
和js一样,ts里的所有数字都是浮点数。 这些浮点数的类型是number。 除了支持十进制和十六进制字面量,ts还支持ECMAScript 2015中引入的二进制和八进制字面量。
// 编译前 let decLiteral: number = 6; // 十进制 let hexLiteral: number = 0xf00d; // 十六进制 let binaryLiteral: number = 0b1010; // 二进制 let octalLiteral: number = 0o744; // 八进制
// 编译后 var decLiteral = 6; // 十进制 var hexLiteral = 0xf00d; // 十六进制 var binaryLiteral = 10; // 二进制 var octalLiteral = 484; // 八进制
布尔类型
最基本的数据类型就是简单的true/false值,在js和ts里叫做boolean(其它语言中也一样)。
// 编译前 let isDone: boolean = false;
// 编译后 var isDone = false;
字符串类型
js程序的另一项基本操作是处理网页或服务器端的文本数据。 像其它语言里一样,我们使用string表示文本数据类型。 和js一样,可以使用双引号(”)或单引号(’)表示字符串。
// 编译前 let name: string = "bob"; name = "smith";
// 编译后 var name = "bob"; name = "smith";
你还可以使用模版字符串,它可以定义多行文本和内嵌表达式。 这种字符串是被反引号包围(),并且以${ expr }这种形式嵌入表达式
// 编译前 let name: string = `Gene`; let age: number = 37; let sentence: string = `Hello, my name is ${ name }.
I'll be ${ age + 1 } years old next month.`;
// 编译后 var name = "Gene"; var age = 37; var sentence = "Hello, my name is " + name + ".\n\nI'll be " + (age + 1) + " years old next month.";
对象类型
和js一样使用对象字面量定义对象一样
// 编译前 let obj: object = { name: 'ts' };
// 或者 let obj: { name: string } = { //这样就限定了obj是一个对象类型且属性必须有name属性 name: 'ts }
// 编译后 var obj = { name: 'ts' };
数组类型
ts像js一样可以操作数组元素。 有两种方式可以定义数组。 第一种,可以在元素类型后面接上[],表示由此类型元素组成的一个数组:
// 编译前 let list: number[] = [1, 2, 3]; // 推荐使用
// 编译后 var list = [1, 2, 3];
第二种方式是使用数组泛型,Array<元素类型>:
// 编译前 let list: Array<number> = [1, 2, 3]; // 不推荐使用
// 编译后 var list = [1, 2, 3];
元组类型
元组类型Tuple允许表示一个已知元素数量和类型的数组,各元素的类型不必相同。 比如,你可以定义一对值分别为string和number类型的元组。
// 编译前 // Declare a tuple type let x: [string, number]; // Initialize it x = ['hello', 10]; // OK // Initialize it incorrectly x = [10, 'hello']; // Error
// 编译后 var x; // Initialize it x = ['hello', 10]; // OK // Initialize it incorrectly x = [10, 'hello']; // Error
这样我们接受和传值的时候就更规范些
任意类型
有时候,我们会想要为那些在编程阶段还不清楚类型的变量指定一个类型。 这些值可能来自于动态的内容,比如来自用户输入或第三方代码库。 这种情况下,我们不希望类型检查器对这些值进行检查而是直接让它们通过编译阶段的检查。 那么我们可以使用any类型来标记这些变量:
// 编译前 let notSure: any = 4; notSure = "maybe a string instead"; notSure = false; // okay, definitely a boolean
// 编译后 var notSure = 4; notSure = "maybe a string instead"; notSure = false; // okay, definitely a boolean
任意类型允许我们随意的变更我们定义的类型,可以更灵活的满足我们的需求
空类型
某种程度上来说,void类型像是与any类型相反,它表示没有任何类型。 当一个函数没有返回值时,你通常会见到其返回值类型是void:
// 编译前 function warnUser(): void { alert("This is my warning message"); }
// 编译后 function warnUser() { alert("This is my warning message"); }
声明一个void类型的变量没有什么大用,因为你只能为它赋予undefined和null:
// 编译前 let unusable: void = undefined;
// 编译后 let unusable = undefined || null;
Null 和 Undefined类型
ts里,undefined和null两者各自有自己的类型分别叫做undefined和null。 和void相似,它们的本身的类型用处不是很大:
// 编译前 // Not much else we can assign to these variables! let u: undefined = undefined; let n: null = null;
// 编译后 // Not much else we can assign to these variables! var u = undefined; var n = null;
默认情况下null和undefined是所有类型的子类型。 就是说你可以把null和undefined赋值给number或者其它类型的变量。
let num: number = 10; num = null; let str: string = 'ts'; str = undefined;
Never类型
never类型表示的是那些永不存在的值的类型。 例如,never类型是那些总是会抛出异常或根本就不会有返回值的函数表达式或箭头函数表达式的返回值类型; 变量也可能是never类型,当它们被永不为真的类型保护所约束时。
never类型是任何类型的子类型,也可以赋值给任何类型;然而,没有类型是never的子类型或可以赋值给never类型(除了never本身之外)。 即使any也不可以赋值给never。
下面是一些返回never类型的函数:
// 返回never的函数必须存在无法达到的终点 function error(message: string): never { throw new Error(message); }
// 推断的返回值类型为never function fail() { return error("Something failed"); }
// 返回never的函数必须存在无法达到的终点 function infiniteLoop(): never { while (true) { } }
当然我们几乎用不到never类型,这里仅当参考
枚举类型
enum类型是对js标准数据类型的一个补充。 像java等其它语言一样,使用枚举类型可以为一组数值赋予友好的名字。
// 编译前 enum Color {Red, Green, Blue} let c: Color = Color.Green; // 1
// 编译后 var Color; (function (Color) { Color[Color["Red"] = 0] = "Red"; Color[Color["Green"] = 1] = "Green"; Color[Color["Blue"] = 2] = "Blue"; })(Color || (Color = {})); var c = Color.Green;
大概实现思路,定义一个变量,然后创建一个匿名自执行函数进行初始化,内部创建同名对象进行动态赋值
// 我们可以看到 Color["Red"] = 0 // 结果可以得到 0 Color[Color["Red"] = 0] = "Red" // 结果可以得到 Red
默认情况下,从0开始为元素编号。 你也可以手动的指定成员的数值。 例如,我们将上面的例子改成从1开始编号:
// 编译前 enum Color {Red = 1, Green, Blue} let c: Color = Color.Green; // 2
// 编译后 var Color; (function (Color) { Color[Color["Red"] = 1] = "Red"; Color[Color["Green"] = 2] = "Green"; Color[Color["Blue"] = 3] = "Blue"; })(Color || (Color = {})); var c = Color.Green;
常见的使用方式是为状态码
enum netWorkStatus { succes = 0, // 表示成功 failed = 404, // 表示失败 error = 500, // 表示服务器出错 }
这样的好处是我们不需要记这些状态码,只需要什么状态取对应值即可,例如 小程序状态码报错节选部分
这样请求成功是我们取netWorkStatus [success]或者netWorkStatus [0],这样就可以拿到0或者success啦。
联合类型
有时候单一的为某个变量指定某个类型满足不了我们的需求,比如一个变量可能是数字或者布尔类型,这样单一的类型满足不了的时候,联合类型就应运而生。联合类型表示一个值可以是几种类型之一。 我们用竖线(|)分隔每个类型,所以number| string| boolean表示一个值可以是number,string,或boolean。
// 编译前 let status: number| boolean = 0; status = true
// 编译后 var status = 0; status = true
类型断言
有时候你会遇到这样的情况,你会比ts更了解某个值的详细信息。 通常这会发生在你清楚地知道一个实体具有比它现有类型更确切的类型。
通过类型断言这种方式可以告诉编译器,“相信我,我知道自己在干什么”。 类型断言好比其它语言里的类型转换,但是不进行特殊的数据检查和解构。 它没有运行时的影响,只是在编译阶段起作用。 ts会假设你,程序员,已经进行了必须的检查。
类型断言有两种形式。 其一是“尖括号”语法:
// 编译前 let someValue: any = "this is a string"; let strLength: number = (<string>someValue).length;
// 编译后 var someValue = "this is a string"; var strLength = someValue.length;
官方例子可能不太懂,那么我们这样写
// 这里我们定义下函数的类型,参数是字符串或者数字类型,返回的是数字类型 type StringLength = (target: string | number) => number
const getStringLength: StringLength = (target) => { if (target.length) { // 这里会报错 因为如果传入的number类型,那么是不具备length属性的 return target.length } else { return target.toString().length } }
// 所以我们用类型断言下 // 这里我们在写逻辑的时候先把传入的值断言成string类型进行我们的业务逻辑,来绕过ts的类型检查 const getStringLength: StringLength = (target) => { if ((target as string).length) { // 这里会报错 因为如果传入的number类型,那么是不具备length属性的 return (target as string).length } else { return target.toString().length } }
另一个为as语法:
// 编译前 let someValue: any = "this is a string"; let strLength: number = (someValue as string).length;
// 编译后 var someValue = "this is a string"; var strLength = someValue.length;
两种形式是等价的。 至于使用哪个大多数情况下是凭个人喜好;然而,当你在ts里使用JSX时,只有as语法断言是被允许的。所以说保险起见还是使用as吧,省心。
讲到最后,如果我们不指定类型的话,ts会进行类型推断,自动帮我们给加上对应的类型。还有不要图省事,一律采用any类型哦。