TypeScript(5):基本数据类型
【思维导图】:
1. let
关键字
JavaScript中使用关键字var来声明变量有很多的缺陷,首先一个就是var作用域的问题。比如:
for (var i = 0; i < 5; i++) { console.log('for循环内,迭代变量i=' + i) } console.log('for循环外:,迭代变量i=' + i)
可想而知,由于使用var声明的变量作用域比较宽松,在for语句等一些语句中,由var声明的变量可能受到外部的干扰而导致运行到非预期的结果。
var在同一区域可以使用相同标识符来声明变量:
var a = 1; var a = "happy"
这也将无意间导致后面可能用到的变量被覆盖。
由于种种缺陷,于是let
应运而生。let声明的变量只在块级有效,并且在一个快中只允许用let声明一个相同标识符的变量。并且如果区块中存在let声明,这个区块对这些命令声明的变量凡是在声明之前就使用他们就会报错,也就是说在含有let的代码块内使用let命令声明变量之前该变量都是不可用的。这是不是很有强类型语言的特点呢?对的,就是借鉴强类型语言的功能过来的。
关于使用
var
、let
、cont
声明变量的更多区别可以参考下一篇博文:
2. 来自JavaScript中的类型
2.1 布尔类型:Boolean
布尔类型是最简单的一种类型,其对象可以被赋予文字值true或者false,对应着真与假或者数字电路中的0或1等等。在JavaScript和TypeScript中布尔类型被叫做boolean
:
let isRight: boolean = false;
Boolean 对象方法
方法 | 描述 |
valueOf() | 返回 Boolean 对象的原始值。 |
【例1】valueOf()方法:
(function(){ let isRight: boolean = false; console.log(isRight.valueOf()) })();
Out[]:
flase
2.2 数字类型:number
这也是来自原生JavaScript的基本类型,不像C、Java等语言数字类型可以分为整形、浮点型等等很多个类型,TypeScript里的所有数字都是浮点数,即TypeScript只有浮点类型用以表示数字,因此数字类型number
与浮点类型等概念。 除了支持十进制和十六进制字面量,TypeScript还支持ECMAScript 2015中引入的二进制和八进制字面量,比如:
let binaryLiteral: number = 0b1010; // 二进制数 let decLiteral: number = 3.14; // 十进制数 let octalLiteral: number = 0o744; // 八进制数 let hexLiteral: number = 0xf00d; // 十六进制数
2.3 字符串类型:String
在TypeScript(或JavaScript)中,字符串类型String
用以表示字符串,与C++、Java等语言不一样,这里即可以使用双引号( "
)来表示字符串,也可以使用单引号('
)表示字符串,因为在TypeScript中,是没有单独的字符类型的,字符只不过是视作只有一个字符的字符串,如:
let a: string = "王者荣耀"; // a 为String类型变量 character = '典韦'; // 给变量character赋值为'典韦'
模板字符串
模版字符串它可以定义多行文本和内嵌表达式, 这种字符串是被反引号包围,并且以${ expr }
这种形式嵌入表达式
let name: string = `Trump`; let age: number = 72; let sentence: string = `Hello, my name is ${ name }. I'll be ${ age + 1 } years old next month.`;
这与下面定义sentence
的方式效果相同:
let sentence: string = "Hello, my name is " + name + ".\n\n" + "I'll be " + (age + 1) + " years old next month.";
String 对象属性
属性 | 描述 |
constructor | 对创建该对象的函数的引用 |
length | 字符串的长度 |
【例1】String 对象属性:
(function(){ let a: string = "你好,欢迎来到TypeScript的世界!"; console.log(a.constructor); console.log(a.length); if(a.constructor==String){ console.log("s是一个字符串") }; })();
Out[]:
ƒ String() { [native code] } 21 s是一个字符串
String 对象方法
方法 | 描述 | 说明 |
charAt() | 返回在指定位置的字符 | |
charCodeAt() | 返回在指定的位置的字符的 Unicode 编码 | |
concat() | 连接字符串 | |
indexOf() | 检索字符串,若指定子字符串出现则返回其第一次出现时首字母在原字符串中的位置 | 如果要检索的子字符串值没有出现,则该方法返回 -1 |
lastIndexOf() | 从后向前搜索字符串,若指定子字符串出现则返回其第一次出现时首字母在原字符串中的位置 | 如果要检索的子字符串值没有出现,则该方法返回 -1 |
localeCompare(target) | 用本地特定的顺序来比较两个字符串 | target 要以本地特定的顺序与 stringObject 进行比较的字符串。 返回说明比较结果的数字: - 如果 stringObject 小于 target, 则 localeCompare() 返回小于 0 的数; - 如果 stringObject 大于 target, 则该方法返回大于 0 的数。 - 如果两个字符串相等,或根据本地排序规则没有区别, 该方法返回 0。 |
match() | 找到一个或多个正则表达式的匹配 | 返回存放匹配结果的数组,若无匹配结果则返回null。 如果匹配的是正则表达式且其具有标志 g,则 match() 方法将执行全局检索,否则 match()只匹配一次。 |
replace() | 替换与正则表达式匹配的子串 | 如果匹配的是正则表达式且其具有标志 g,则 replace() 方法将执行全局替换,否则只替换一次 |
search() | 检索与正则表达式相匹配的值 | 如果没有找到任何匹配的子串,则返回 -1; 否则返回第一个与 正则表达式 相匹配的子串的起始位置。 |
slice() | 提取字符串的片断,并在新的字符串中返回被提取的部分 | |
split() | 把字符串分割为字符串数组 | |
toLocaleLowerCase() | 把字符串转换为小写 | |
toLocaleUpperCase() | 把字符串转换为大写 | |
toLowerCase() | 把字符串转换为小写 | |
toUpperCase() | 把字符串转换为大写 | |
toString() | 返回字符串 | |
valueOf() | 返回某个字符串对象的原始值 |
【例】String 对象的方法使用示例1
(function(){ let a1: string = "你好,"; let a2: string = "TypeScript的世界欢迎来到!"; let a3: string = "我将和你一起,畅游于此..."; console.log("a1.charAt(1): "+a1.charAt(1)); console.log("a1.charCodeAt(1): "+a1.charCodeAt(1)); console.log("a1.concat(a2,a3): "+a1.concat(a2,a3)); console.log("a2.indexOf('Type'): "+a2.indexOf("Type")); console.log("a2.lastIndexOf('界'): "+a2.lastIndexOf("界")); console.log("'二月'.localeCompare('二月'): "+"二月".localeCompare("二月")); // 字符串完全一样 console.log("'五月'.localeCompare('七月'): "+"五月".localeCompare("七月")); // 可以识别中文数字,七月在五月之后。 console.log("'七月'.localeCompare('五月'): "+"七月".localeCompare("五月")); // 五月在七月之前。不匹配也一样为负值。 console.log("英语考试结束了后李华的心情是7 上8 下。".match(/\d+/g)); console.log("现在时间是2020年12月12日".replace(/\d{4}年(\d{2})月\d{2}日/g,"2021年4月12日")); console.log("现在时间是2020年12月12日".search(/\d{4}年(\d{2})月\d{2}日/g)); // 返回第一个2出现的索引号 })();
Out[]:
a1.charAt(1): 好 a1.charCodeAt(1): 22909 a1.concat(a2,a3): 你好,TypeScript的世界欢迎来到!我将和你一起,畅游于此... a2.indexOf('Type'): 0 9 a2.lastIndexOf('界'): 12 '二月'.localeCompare('二月'): 0 '五月'.localeCompare('七月'): 1 '七月'.localeCompare('五月'): -1 ["7", "8"] 现在时间是2021年4月12日 5
【例】String 对象的方法使用示例2
(function(){ let a: string = "你好,欢迎来到TypeScript的世界!"; console.log(a.slice(3)); console.log(a.slice(0,2)); console.log(a.slice(7,17)); })();
Out[]:
欢迎来到TypeScript的世界! 你好 TypeScript
【例】String 对象的方法使用示例3
(function(){ let a: string = "你好,欢迎来到TypeScript的世界!"; console.log(a.split("")); // 拆分所有字符 console.log(a.split(",")); // 按指定字符进行拆分 })();
Out[]:
["你", "好", ",", "欢", "迎", "来", "到", "T", "y", "p", "e", "S", "c", "r", "i", "p", "t", "的", "世", "界", "!"] ["你好", "欢迎来到TypeScript的世界!"]
【例】String 对象的方法使用示例4
(function(){ let a: string = "I love China!"; console.log(a.toLocaleLowerCase()); console.log(a.toLocaleUpperCase()); console.log(a.toLowerCase()); console.log(a.toUpperCase()); })();
Out[]:
// 不论大写还是小写也改变不了我们的中国心I♥Chian i love china! I LOVE CHINA! i love china! I LOVE CHINA!
2.4 数组
TypeScript像JavaScript一样可以操作数组元素。 有两种方式可以定义数组。 第一种,可以在元素类型后面接上 []
,表示由此类型元素组成的一个数组:
let list: number[] = [1, 2, 3];
第二种方式是使用数组泛型,Array<元素类型>
:
let list: Array<number> = [1, 2, 3];
Array 对象方法
方法 | 描述 |
concat() | 连接两个或更多的数组,并返回结果。 |
join() | 把数组的所有元素放入一个字符串。元素通过指定的分隔符进行分隔。 |
pop() | 删除并返回数组的最后一个元素 |
push() | 向数组的末尾添加一个或更多元素,并返回新的长度。 |
reverse() | 颠倒数组中元素的顺序。 |
shift() | 删除并返回数组的第一个元素 |
slice() | 从某个已有的数组返回选定的元素 |
sort() | 对数组的元素进行排序 |
splice() | 删除元素,并向数组添加新元素。 |
toSource() | 返回该对象的源代码。 |
toString() | 把数组转换为字符串,并返回结果。 |
toLocaleString() | 把数组转换为本地数组,并返回结果。 |
unshift() | 向数组的开头添加一个或更多元素,并返回新的长度。 |
valueOf() | 返回数组对象的原始值 |
【例】concat()
(function(){ let list_1: number[] = [1, 2, 3]; let list_2: number[] = [4, 5, 6]; console.log(list_1.concat(list_2)); //也可以用list_1.concat(4,5,6) })();
Out[]:
[1, 2, 3, 4, 5, 6]
另见元组
元组是TypeScript中对JavaScript扩展的类型,见 3.4 元组 部分。
2.5 对象类型:Object
object
表示非原始类型,也就是除number
,string
,boolean
,symbol
,null
或undefined
之外的类型。
使用object
类型,就可以更好的表示像Object.create
这样的API。例如:
declare function create(o: object | null): void; create({ prop: 0 }); // OK create(null); // OK create(42); // Error create("string"); // Error create(false); // Error create(undefined); // Error
2.6 空类型:Void
某种程度上来说,void
类型像是与any
类型相反,它表示没有任何类型。 当一个函数没有返回值时,你通常会见到其返回值类型是 void
:
function warnUser(): void { console.log("This is my warning message"); }
声明一个void
类型的变量没有什么大用,因为你只能为它赋予undefined
和null
:
let unusable: void = undefined;
2.7 Null类型 和 Undefined类型
TypeScript里,undefined
和null
两者各自有自己的类型分别叫做undefined
和null
。 和 void
相似,它们的本身的类型用处不是很大:
// Not much else we can assign to these variables! let u: undefined = undefined; let n: null = null;
默认情况下null
和undefined
是所有类型的子类型。 就是说你可以把 null
和undefined
赋值给number
类型的变量。
然而,当你指定了--strictNullChecks
标记,null
和undefined
只能赋值给void
和它们各自。 这能避免 很多常见的问题。 也许在某处你想传入一个 string
或null
或undefined
,你可以使用联合类型string | null | undefined
。 再次说明,稍后我们会介绍联合类型。
注意:我们鼓励尽可能地使用
--strictNullChecks
,但在本手册里我们假设这个标记是关闭的。
3. TypeScript拓展的类型
3.1 枚举类型:enum
枚举类型用于声明一组命名的常数,当一个变量有几种可能的取值时,可以将它定义为枚举类型。 使用枚举类型可以为一组数值赋予友好的名字。如:
enum Color {Red, Green, Blue} // 枚举类型中为声明标识符会当作常量来处理,常量值默认为从0开始编号的数字 let c: Color = Color.Green;
默认情况下,从0
开始为元素编号。 你也可以手动的指定成员的数值。 例如,我们将上面的例子改成从 1
开始编号:
enum Color {Red = 1, Green, Blue} let c: Color = Color.Green;
或者,全部都采用手动赋值:
enum Color {Red = 1, Green = 2, Blue = 4} let c: Color = Color.Green;
枚举类型提供的一个便利是你可以由枚举的值得到它的名字。 例如,我们知道数值为2,但是不确定它映射到Color里的哪个名字,我们可以查找相应的名字:
enum Color {Red = 1, Green, Blue} let colorName: string = Color[2]; console.log(colorName); // 显示'Green'因为上面代码里它的值是2
3.2 any类型
any类型用于标记编程阶段还不清楚类型的变量,直接让它们通过编译阶段的检查。
let notSure: any = 4; notSure = "maybe a string instead"; notSure = false; // okay, definitely a boolean
在对现有代码进行改写的时候,any
类型是十分有用的,它允许你在编译时可选择地包含或移除类型检查。 你可能认为 Object
有相似的作用,就像它在其它语言中那样。 但是 Object
类型的变量只是允许你给它赋任意值 - 但是却不能够在它上面调用任意的方法,即便它真的有这些方法:
let notSure: any = 4; notSure.ifItExists(); // okay, ifItExists might exist at runtime notSure.toFixed(); // okay, toFixed exists (but the compiler doesn't check) let prettySure: Object = 4; prettySure.toFixed(); // Error: Property 'toFixed' doesn't exist on type 'Object'.
当你只知道一部分数据的类型时,any
类型也是有用的。 比如,你有一个数组,它包含了不同的类型的数据:
let list: any[] = [1, true, "free"]; list[1] = 100;
3.3 Never类型
never
类型表示的是那些永不存在的值的类型;never
类型是任何类型的子类型,也可以赋值给任何类型;- 没有其它类型(即使是any)是
never
的子类型或可以赋值给never
类型;
例如, never
类型是那些总是会抛出异常或根本就不会有返回值的函数表达式或箭头函数表达式的返回值类型; 变量也可能是 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) { } }
3.4 元组类型
元组类型允许表示一个已知元素数量和类型的数组,各元素的类型不必相同。 比如,你可以定义一对值分别为 string
和number
类型的元组。
let x: [string, number]; // 声明一个元组 x = ['hello', 10]; // 初始化该元组,元素数据类型应该和声明时的保持一致 x = [10, 'hello']; // 这样初始化不正确
当访问一个已知索引的元素,会得到正确的类型:
console.log(x[0].substr(1)); // OK console.log(x[1].substr(1)); // Error, 'number' does not have 'substr'
TypeScript中数组和元组的区别:
- 数组内可以存储任意类型数据
当访问一个越界的元素,会使用联合类型替代:
x[3] = 'world'; // OK, 字符串可以赋值给(string | number)类型 console.log(x[5].toString()); // OK, 'string' 和 'number' 都有 toString x[6] = true; // Error, 布尔不是(string | number)类型
联合类型的详细内容可以参考另外一篇博文:TypeScript笔记(9):联合类型