本文为系列文章《TypeScript系列》中的第二篇文章 -- 数据类型与断言。

在上一篇文章作者介绍了TypeScript的一些基本的特性和特点并且和JavaScript之间的一些区别,具体文章请参考此链接。

基础变量声明

在TypeScript当中的变量声明方式从整体语法结构来看与JavaScript类似,但是有一些细微的差别:

/*
	let [变量]:[类型] = 值
*/let count : number = 10;console.log(count); // 10复制代码

这种方式实现的变量命名有一个好处,,那就是赋值语句中等号右侧值的类型和等号左侧自行定义的值的类型必须得是完全一致的,否则会报错。.

如果赋值的时候传入的是正确的数值后期又重新赋值了错误类型的值,同样也会报错。

let str:string;if (str === undefined) { // undefined是任何类型的子类型str = '巧克力很苦';console.log(str); // 巧克力很苦}// str = 10 // 不能将类型“number”分配给类型“string”console.log(str);复制代码

let [变量]:[类型] = 值

  • 如果只是创造了变量并规定了类型,那么这个变量默认的值就是undefined。
  • 如果只是写了一条没有确定类型的变量声明语句,那么这个变量用起来的时候就是undefined,但是一旦后面有其他的新的赋值操作,还是会按照变量的预设格式来的。
数据类型

TypeScript 和 JavaScript 的不同点之一就是TypeScript变量是强类型的( 我就是我,谁也改变不了)。简单来说就是,如果声明的变量没有声明为any类型,就不能随意的把这个变量赋值为其他类型的值。来,开始上代码。

let a = 1;// a = 'hello' // error 报错,因为a会默认声明为number类型,不能赋值字符串类型的值let b:any = 1;
b = 'hello'//赋值成功复制代码

在TypeScript当中基本数据类型一共分为boolean,number,string,array,tuple,enum,any,void,undefined,null,never,object一共12种类型。

有JavaScript基础的小伙伴,对上面部分的数据类型是比较熟悉的。但是有一些很陌生呀,请不要着急接下来我们来说一说这10多种类型的使用方法。

布尔类型(boolean)

布尔值是最基础的数据类型,在 TypeScript 中,使用 boolean 定义布尔值类型:

// 布尔值let isBoolean: boolean = false;console.log(isBoolean); // false// 后面的约定未强调编译错误的代码片段,默认为编译通过。复制代码

注意,使用构造函数 Boolean 创造的是对象并不是布尔值。

let booleanObj: boolean = new Boolean(1); // error// 不能将类型“Boolean”分配给类型“boolean”。// “boolean”是基元,但“Boolean”是包装器对象。如可能首选使用“boolean”。复制代码

实际上 new Boolean() 返回的结果是一个 Boolean 对象。

let booleanObj: Boolean = new Boolean(1);复制代码

直接调用 Boolean 函数,也可以返回一个 boolean 类型。

let booleanObj: boolean = Boolean(1);复制代码

在 TypeScript 中,boolean 是 JavaScript 中的基本类型,而 Boolean 是 JavaScript 中的构造函数。 其他基本数据类型(除了 null 和 undefined)构造器表现都一样,不再进行单独的描述了。

数字类型(number)

和JavaScript一样,TypeScript里的所有数字都是浮点数。 这些浮点数的类型是number。 除了支持十进制和十六进制字面量,TypeScript还支持ECMAScript 2015中引入的二进制和八进制字面量。

let decLiteral: number = 6;let hexLiteral: number = 0xf00d;let binaryLiteral: number = 0b1010;let octalLiteral: number = 0o744;复制代码

字符串类型(string)

在JavaScript程序的另一项基本操作是处理网页或服务器端的文本数据。 像其它语言里一样,我们使用string表示文本数据类型。 和JavaScript一样,可以使用双引号(")或单引号(')表示字符串。

let qkl: string = "巧克力";
qkl = "巧克力很苦";复制代码

你还可以使用模版字符串,它可以定义多行文本和内嵌表达式。 这种字符串是被反引号包围,并且以${ name}这种形式嵌入表达式 。

let name: string = `Gene`;let age: number = 37;let desc: string = `Hello, my name is ${ name }.

I'll be ${ age + 1 } years old next month.`;复制代码

这与下面定义desc的方式效果相同:

let sentence: string = "Hello, my name is " + name + ".\n\n" +"I'll be " + (age + 1) + " years old next month.";复制代码

数组类型(array)

TypeScript像JavaScript一样可以操作数组元素。 有两种方式可以定义数组。

第一种,可以在元素类型后面接上[],表示由此类型元素组成的一个数组。

let list: number[] = [1, 2, 3];复制代码

**第二种方式是使用数组泛型,Array<元素类型>。 **

let list: Array<number> = [1, 2, 3];复制代码

元组类型(tuple)

元组类型属于数组的一种,而上面一种数组里面只能有一种类型,否则会报错,而元组类型内部可以有多种类型(元组类型表示一个已知元素数量和类型的数组,各元素的类型不必相同)。

比如,你可以定义一对值分别为string和number类型的元组。

// 声明一个元组类型let x: [string, number];
x = ['hello', 10]; // OK// x = [10, 'hello']; // Error 初始化错误复制代码

当访问一个已知索引的元素,会得到正确的类型。

console.log(x[0].substr(1)); // OK// console.log(x[1].substr(1)); // Error, 错误,'number'没有'substr'复制代码

当我们访问一个越界的元素,会使用联合类型替代。

x[3] = 'world'; // OK, 字符串可以赋值给(string | number)类型console.log(x[5].toString()); // OK, 'string' 和 'number' 都有 toString// x[6] = true; // Error, 布尔不是(string | number)类型复制代码

枚举类型(enum)

enum枚举类型是对JavaScript标准数据类型的一个补充。 像C#等其它语言一样,使用枚举类型可以为一组数值赋予变量名称。

enum Color {Red, Green, Blue}复制代码

以上的代码编译成JavaScript代码

var Color;
(function (Color) {
    Color[Color["Red"] = 0] = "Red";
    Color[Color["Green"] = 1] = "Green";
    Color[Color["Blue"] = 2] = "Blue";
})(Color || (Color = {}));复制代码

在默认情况下,enum从0开始为元素编号。( 如果没有给标识符赋值,那么标识符的值默认为索引值)。

你也可以手动的指定成员的数值,如果只给第一个设置编号,那么你设置这个编号将成为起始编号,如果每个都设置,相当于手动设置每个元素的下标。

/*
    enum 枚举名{
       标识符=整形常数,
       标识符=整形常数,
       ......
       标识符=整形常数
    };
    定义一个枚举类型
*/enum ColorIndex {Red = 1, Green = 10, Blue = 5}// 输出// { '1': 'Red', '5': 'Blue', '10': 'Green', Red: 1, Green: 10, Blue: 5 } 复制代码

enum的类型的值里面不能设置为对象,或者是利用变量的间接引用对象的值。

enum Color = {Red = 1, {"y":1}, Blue} // 报错// 或者是let o = {x:1}enum ColorTwo = {Red = 1, o, Blue} // 报错复制代码

枚举类型提供的一个便利原则就是你可以由枚举的值得到它的名字。

例如,我们知道数值为2,但是不确定它映射到Color里的哪个名字,我们可以查找相应的名字:

enum Color {Red = 1, Green, Blue}let colorName: string = Color[2]console.log(colorName); // 显示'Green',因为上面的代码里面的值是2复制代码

任意类型(any)

**有时候,我们会想要为那些在编程阶段还不清楚类型的变量指定一个类型。**这些值可能来自于动态的内容,比如来自用户输入或是从后端请求来的数据

这种情况下,我们不希望类型检查器对这些值进行检查而是直接让它们通过编译阶段的检查。 那么我们可以使用 any类型来标记这些变量。

let myName : any = 4console.log(myName); // 4myName = '巧克力' console.log(myName)// 巧克力myName = {name: '巧克力',age:18}console.log(myName); // {name:'巧克力',age:18}复制代码

void类型

TypeScript中的void表示没有任何类型,一般用于定义方法的时候没有返回值,虽然也能给变量指定类型,但是void类型只能被赋值undefined和null,其实没有什么实际意义 。

在TypeScript中函数的void类型表示其返回值的类型,函数类型为void表示其没有返回值。

function run() : void {console.log(123);// return 不能有返回值,否则会报错}function fun1() : number {console.log(345);return 123 // 必须有返回值,并且返回值必须是number值,否则会报错}function fun2() : any {console.log(789); // 因为any是任意类型,所以也可以不要返回值}复制代码

undefined和null类型

虽然为变量指定了类型,但是如果不赋值的话默认该变量还是undefined类型,如果没有指,undefined直接使用该变量的话会报错,只有自己指定的是undefined类型才不会报错。

let flag : undefined;/*
    或者是 let flag:undefined=undefined;
*/console.log(flag); // undefinedlet flag1 : null = null; // 如果不指定值为null那么打印的时候也会报错console.log(flag1); // null复制代码

默认情况下null和undefined是所有类型的子类型,就是说你可以把null和undefined赋值给number类型的变量。

let num : number = undefinedlet str : string = null复制代码

为变量指定多种可能的类型。

// 为变量指定多种可能的类型let one : number | undefined; // 这种写法就不会在没有赋值的时候报错了,因为你设置了可能为undefinedconsole.log(one);
one = 123console.log(flag); // 123可以改完数值类型// 也可以设定多个类型let tow : number | string | null | undefined;
tow = 123;console.log(tow); //123tow = null;console.log(tow); //nulltow = "string";console.log(tow); //string复制代码

never类型

never 类型表示的是那些永不存在的值的类型。

这个严格来说算不上啥新的数据类型,只是开发者对于一类值所起的作用的判断而已。

比如:

  1. 总是会抛出异常, throw错误或是返回一个error类型的数据。
  2. 根本就不会有返回值的函数表达式(死循环函数)。
// 返回never的函数必须存在无法达到的终点function error (message:string) : never {throw new Error(message);
}// 推断的返回值的类型为neverfunction fail () : never {return error('Something failed')
}// 返回never的函数必须存在无法达到的终点function infiniteLoop () : never {while (true) {}
}复制代码

never类型是其他类型(包括null和undefine)的子类型,代表着从来不会出现的值,意为这声明never类型的变量只能被never类型所赋值,即使any类型也不可以赋值给never。

let c : never; // c变量不可以被任何数据类型赋值,包括null和undefined,之不会出现的值let n : stringn = '666'c = '哈哈' // 报错// 不报错,一个抛出错误的函数就是never类型的c = (() => {throw new Error('error')
})()// 不报错,never类型的数据可以赋值给其他类型的变量n = (() => {   throw new Error('error') 
})()复制代码

object类型

object表示非原始类型,也就是除number,string,boolean,symbol,null或undefined之外的类型 。

let stu : object = {name: '张三',age:18}console.log(stu); // {name: '张三', age:18}// 也可以let stuTwo : {} = {name: '张三',age:18}console.log(stuTwo);// 或者是我们限时当前object对象里面的属性和值的类型let obj: {name: string, age: number} = {name: '巧克力', age: 18}console.log(obj);复制代码
declare function create(o: object | null): void;//declare是一个声明的关键字,可以写在声明一个变量时解决命名冲突的问题create({ prop: 0 }); // OKcreate(null); // OKcreate(42); // 报错create("string"); // 报错create(false); // 报错create(undefined); // 报错复制代码
类型断言

有时候你会遇到这样的情况,你会比TypeScript更了解某个值的详细信息。

通常这会发生在你清楚地知道一个变量具有比它现有类型更确切的类型(比如说满是数字的数组,或是全都是自然数下标的对象,这只是一个举例)。

通过类型断言这种方式可以告诉编译器,“相信我,我知道自己在干什么” ,类型断言好比其它语言里的类型转换,但是不进行特殊的数据检查和解构。

它没有运行时的影响,只是在编译阶段起作用。 TypeScript会假设你,程序员,已经进行了必须的检查。

类型断言有两种方式

  1. 尖括号写法

    let someValue : any = 'this is a string'// 如果写的是any找字符串的length属性的话,编译器是找不到length属性的// 类型断言断言后是可以知道的let strLength : number = (<string>someValue).lengthconsole.log(strLength);复制代码
  2. as语法

    let someValue : any = 'this is a string'let strLength : number = (someValue as string).lengthconsole.log(strLength);复制代码

注意: 两种形式是等价的,但是当在TypeScript里使用JSX时,只有as语法断言是被允许的。

最后

本章节:思维导图

TypeScript系列--数据类型与断言_断言

下一章节我们主要讲解typescript的interface接口设计,请大家敬请期待。

文章发布时间:2021-1-3。