基本数据类型
我们都知道js有6种基本数据类型:布尔、数字、字符串、null、undefined和es6新增的Symbol + 1种引用数据类型:对象(包含Object、Function、Array、Date等等)类型。
ts作为js的超集,ts也有一套数据类型和上述7中数据类型进行一一对应。这里我们先介绍5中基本类型:布尔、数字、字符串、null和undefined,Symbol暂时不会提到。
基本数据类型,它有两个值:true/false。在ts中是这样表示一个bool值的:
const isDone: boolean = false; 值得注意的是,不能将构造函数Boolean实例化的值赋给boolean:
const isDone: boolean = new Boolean(false);
不能将类型“Boolean”分配给类型“boolean”。 “boolean”是基元,但“Boolean”是包装器对象。如可能首选使用“boolean”。 实际上,new Boolean()返回的类型是Boolean,并非boolean:
// 正常编译通过(后面没有标明错误的都表示正常编译通过) const isDone: Boolean = new Boolean(false); 我们需要区分清楚,boolean是js的基本数据类型,而Boolean是js中的构造函数,返回的对象是以Boolean为原型的js对象,使用ts的时候要注意这个区别。包括后面的其他数据类型也是一样的问题,后面不再赘述。
基本数据类型,js和ts中的数字全部都是浮点数。在ts中表示一个数值:
let decLiteral: number = 6; // 十六进制 let hexLiteral: number = 0xf00d; // 二进制 let binaryLiteral: number = 0b1010; // 八进制 let octalLiteral: number = 0o744;
基本数据类型,js和ts都可以使用 " 符号或者 ’ 符号包裹来表示字符串,也可以使用模板字符串 ` 符号进行包裹:
let str: string = ‘前端充电’; let name: string = “aaa”;
// 使用模板字符串 let tempStr: string = 欢迎关注 {str}; Null和undefined
这两个基本数据类型,同样可以在ts中分别使用null和undefined来表示:
let u: undefined = undefined; let n: null = null; 默认情况下,null和undefined是其他类型的子类型。什么意思呢?也就是说,你可以将null和undefined赋值给其他类型的数据而不会编译报错。例如:
let age: number = undefined; let people: string = null; 如果你在自己的项目中尝试的时候发现报错了,可以试试查看下项目文件中有没有一个tsconfig.json的文件:
这是ts的配置文件,里面可以定制化自己的ts规则。比如上面所讲的可以将null和undefined赋值给其他类型也是可以定制化的。修改配置文件里面的strictNullChecks属性为true,就会发现上述两行代码就会报错了:
let age: number = undefined; let people: string = null;
不能将类型“undefined”分配给类型“number”。 不能将类型“null”分配给类型“string”。 strictNullChecks就表示是否只允许null和undefined赋值给void类型和它们各自的类型,ts官方建议这个配置默认为true,可以避免问题查找过于混乱。
上面提到了void类型,这个是ts独有的类型。可以理解为空值,表示没有任何类型。声明为void的变量只能赋值为null或者undefined:
let age: void = undefined; 这里插播一点,null可以赋值给void是ts官方的定义。但是我亲自测试的时候发现无论是变量的null还是函数返回值null赋值给void都会报错。所以关于null是否能赋值给void这一点还有待确定,当然如果你知道原因的话也可以留言给我解答一下,这里我不能随意带过所以就提出来了。
let name: void = null; let result = (): void => null;
不能将类型“null”分配给类型“void”。 好,我们接着往下看。void除了可以赋值为undefined,还可以表示没有返回值的函数:
// (): void的写法表示函数的返回值类型,详细的会在后面函数部分讲到。 let getData = (): void => console.log(‘这里没有任何返回值。’); 要注意的是,没有返回值的函数并非是指返回undefined,实际上它的返回值类型就是void。所以要注意不要定义函数返回类型为undefined,下面的写法会报错:
let getData = (): undefined => console.log(‘这里没有任何返回值。’)
不能将类型“void”分配给类型“undefined”。ts独有类型,有时候我们还不能确定一个变量到底会被赋予什么类型的值的时候,就可以定义为any类型。any表示可以是任意的类型:
let a: any = 1; let b: any = true; let c: any = null; any可以在编译过程中被赋予任意类型的值:
let a: any = 1; a = undefined; a = ‘字符串’; 可以任意访问any类型的内部属性:
let a: any; console.log(a.anyProp.anyOtherFn()); 在声明变量的时候未指定类型也会被识别为any类型:
let a; a = ‘任意类型’; a = 2; 一定要尽量避免使用any!!!否则ts就和js没什么差别了!
never
ts独有的类型,表示永远不会存在的值的类型。never类型的值可以赋值给任意类型,但是除了never类型,没有其他类型可以赋值给never类型,即使是any类型也不行;
let neverType: never; let anyType: any; neverType = anyType;
不能将类型“any”分配给类型“never”。 never类型一般使用在那些总是会抛出异常的函数中:
function throwErr(): never { throw new Error(‘something throng’); 又或者是无法结束循环的函数中:
function infiniteLoop(): never { while(true) {} 引用数据类型
上面我们提到js有1种引用数据类型:对象。实际上对象是一种统称,因为在js中万物皆对象。对象包含了js对象、数组、函数等等引用类型,我们逐步看看ts又是如何表示这些类型的。(后面提到的对象指代js通过new Object创建出来的对象)
引用数据类型,这里ts就不能简单地通过某一种类型来对其进行描述啦。因为对象的可能性是无限的,不能通过某种类型来单一定义。
ts中使用接口(interface)来定义对象。所谓接口其实跟传统意义上的面向对象的接口有些差别,传统意义上的接口更多是对行为的抽象化,而ts的接口是描述一个对象的形状(shape)。
我们直接来看下面的例子:
interface IAnimal { name: string; eat (): void; 上面定义了Animal接口,ts中规定interface的第一个字母必须是大写的"i"。IAnimal有一个name属性是string类型,有一个返回值是void的eat方法。下面我们根据这样的接口定义变量:
let cat: IAnimal = { name: ‘Tom’, eat () { console.log(‘喝牛奶’); 上面我们定义了cat变量为IAnimal类型,并且给name变量赋了值还有实现了eat方法,这就是接口的最简单的使用。
只要有缺失的属性,ts编译就会报错:
interface IAnimal { name: string; eat (): void; let cat: IAnimal = { name: ‘Tom’ 类型 “{ name: string; }” 中缺少属性 “eat”,但类型 “IAnimal” 中需要该属性。 同样的,有多余的属性编译也是不通过的:
interface IAnimal { name: string; eat (): void; let cat: IAnimal = { name: ‘Tom’, eat () { console.log(‘喝牛奶’); age: 18 不能将类型“{ name: string; eat(): void; age: number; }”分配给类型“IAnimal”。 对象文字可以只指定已知属性,并且“age”不在类型“IAnimal”中。 接口可以定义可选属性,表示该属性可以存在也可以不存在。可选属性定义如下:
interface IAnimal { name: string; eat (): void; age?: number; 这时候无论实现的对象是否包含age属性都不会报错:
let cat: IAnimal = { name: ‘Tom’, eat () { console.log(‘喝牛奶’); age: 18 接口可以定义任意属性,任意属性允许我们传入一个任意的变量,一个接口只允许定义一个任意属性:
interface IAnimal { name: string; eat (): void; age?: number; propName: string: any;
let cat: IAnimal = { name: ‘Tom’, eat () { console.log(‘喝牛奶’); age: 18, anyProp: ‘这是任意变量’, anyProp2: true 任意属性涉及到的点有点多。。。我们一一来理一下。
首先是IAnimal中的propName: string: any这句话:
接口如果定义了这句话,你就可以在具体的对象中放置任意数目的属性而不用担心编译错误。propName: string表示的是最终只会取键类型是string的值,所以如果键的类型是number、symbol等等最后是不会存在cat中的。
上面的any表示的是允许的值类型,要注意一旦定义了任意属性,那么确定属性和可选属性都必须是任意类型的子集。例如下面的任意属性就会报错:
interface IAnimal { name: string; eat (): void; age?: number; propName: string: string; 类型“() => void”的属性“eat”不能赋给字符串索引类型“string”。 类型“number | undefined”的属性“age”不能赋给字符串索引类型“string”。 因为任意属性定义的类型是string,所以其他属性必须为string。所以这也是为什么要在特定场合才使用任意属性的原因,限制太多。
接口可以定义只读属性,只需要在前面添加一个readonly即可:
interface IAnimal { readonly name: string; eat (): void; age?: number; 当我们打算为只读属性赋值就会报错:
let cat: IAnimal = { name: ‘Tom’, eat () { console.log(‘喝牛奶’); age: 18, cat.name = ‘Jerry’;
无法分配到 “name” ,因为它是只读属性。下面来看看第二种常见的类型:数组。数组可以使用3种方式来定义,但是有一些不是ts官方建议使用的,这里我们都来看一下。
第一种:类型 + 方括号表示法(推荐)
const arr: number[] = [1, 2, 3]; 这是最简单的数组表示方法,number表示数组每一项的类型必须为number。
第二种:泛型
关于泛型的详细讲解我放在了下一篇ts进阶文章,这里大概看一下其写法就行了:
const arr: Array = [1, 2, 3]; Array后面接尖括号,里面的number参数就表示数组的每一项必须是number,约束和第一种写法是一样的。
第三种:接口
还记得我们刚刚讲过的任意属性吗?可以利用它来表示数组:
interface IArr { [i: number]: number
let arr: IArr = [ 1, 2, 3 ]; 这种用法真的很巧妙!不过我们一般不推荐这种用法,比较复杂而且可读性差。
如果我们想要一个存放任意类型数据的数组,可以定义any类型的数组:
let arr: any[] = [ 1, true, 2, ‘这是任意类型数组’ ];
接下来我们看一下函数类型,我们前面也已经有写过部分函数类型了:
let getData = (): void => console.log(‘这里没有任何返回值。’); 这是函数表达式搭配es6箭头函数的写法(ts原生语法就支持es6),函数不接受参数,返回值是void类型,也就是不返回任何值。
函数可以接收参数,参数的类型需要指定:
function add(num1: number, num2: number): number { return num1 + num2; 函数还可以通过函数表达式的方式定义:
let sum = (num1: number, num2: number): number => num1 + num2; 但是通过函数表达式定义的函数有个问题,就是左侧的sum变量还没有为它赋予类型。要为sum赋予类型的话,必须赋值为完整的函数类型,包含参数和返回值:
let sum: (num1: number, num2: number) => number = (num1: number, num2: number): number => num1 + num2; 注意上面的 => number和下面的箭头函数=> num1 + num2的差别,第一个是ts语法中的表示函数执行后返回值类型,第二个则是箭头函数特定写法。
函数可以定义可选参数和默认参数
和接口类似,函数的参数类型可以为可选参数,可以为参数添加默认参数。我们看个例子:
function add(num1: number, num2: number, isDouble?: boolean): number { return isDouble ? (num1 + num2) * 2 : (num1 + num2);
add(1, 2); // 3 add(2, 5, true); // 14 上面函数中定义了一个可选参数:isDouble,调用者可以选择是否传递该参数,如果不传的话就是undefined。要注意可选参数不允许出现在必选参数前面:
function add(isDouble?: boolean, num1: number, num2: number): number { return isDouble ? (num1 + num2) * 2 : (num1 + num2); 必选参数不能位于可选参数后。 原因也很容易理解,可选参数在前面的话调用者就没办法传参了。下面我们来看下默认参数写法:
function add(num1: number, num2: number, isDouble?: boolean, coefficient: number = 2): number { return isDouble ? (num1 + num2) * coefficient : (num1 + num2);
add(1, 2); // 3 add(4, 6, true); // 20 add(4, 6, true, 3); // 30 这里增加多了一个默认参数:coefficient,和js函数的默认参数定义是一样的,如果没有传递则用默认值。
函数可以通过…rest来接收剩余参数
你可以通过一个变量来收集所有的参数:
function eat(food: string, …rest: string[]): void { console.log(‘eat:’, food, rest);
eat(‘香蕉’, ‘菠萝’, ‘苹果’); // eat: 香蕉 [“菠萝”, “苹果”] 这个变量实际上就是一个数组,要注意它同样得放到参数最后面(在可选参数之后)。
ts可以根据上下文语境动态推断类型。
在没有指定类型的时候推断: let str = ‘字符串1’;
// 等价于
let str: string = ‘字符串1’; 在定义时没有赋值: let str;
//等价于
let str: any;
联合类型用于表示变量可能取值为多个变量之一,如下:
let a: string | number; 变量a的可能取值是string或者number,在赋值之前它的类型都是不确定的状态。但是如果给它赋予其它类型的值就会报错:
a = true;
不能将类型“true”分配给类型“string | number”。 当联合类型不能确定是哪种类型时,我们只能访问两种类型都存在的属性或者方法,否则就会编译错误。
let a: string | number; console.log(a.length);
类型“string | number”上不存在属性“length”。 类型“number”上不存在属性“length”。 当为变量赋值之后,其类型也就确定下来了,无法再使用另一个类型的属性。
let a: string | number = 12; console.log(a.length);
类型“number”上不存在属性“length”。 ———————————————— 版权声明:本文为CSDN博主「learntogiveup」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接: blog.csdn.net/learntogive…