typeScript 学习总结(基础篇)
typeScript 数据类型
原始数据类型(Primitive data types)
原始数据类型:布尔值(boolean)/数值(number)/字符串(string)/null
/undefined
/ES6中的Symbol
类型
定义类型语法:
let varName: type = [对应类型的赋值]; //也可单独赋值
布尔值(使用boolean
定义类型)
定义如下:
let flag: boolean = true;
PS:使用构造函数Boolean
创造的对象不是布尔值而是一个Boolean
对象。
比如:
let createByNewBoolean: boolean = new Boolean(1);
报错:
下面这个就对了,Boolean是js的内置对象,typeScript中定义好了,可以直接当类型定义,表示一个Boolean对象
let createByNewBoolean: Boolean = new Boolean(1);
数值类型(number)
let decLiteral: number = 6;
let hexLiteral: number = 0xf00d;
// ES6 中的二进制表示法
let binaryLiteral: number = 0b1010;
// ES6 中的八进制表示法
let octalLiteral: number = 0o744;
let notANumber: number = NaN;
let infinityNumber: number = Infinity;
编译结果:
var decLiteral = 6;
var hexLiteral = 0xf00d;
// ES6 中的二进制表示法
var binaryLiteral = 10;
// ES6 中的八进制表示法
var octalLiteral = 484;
var notANumber = NaN;
var infinityNumber = Infinity;
其中 0b1010
和 0o744
是ES6 中的二进制和八进制表示法,它们会被编译为十进制数字。
字符串(string)
let name: string = 'Tom'
编译结果:
let name = 'Tom'
空值(void)
js中没有空值(void)的概念。在typeScript中,类比C语言等强类型编程语言,可以用void
表示没有任何返回值的函数,如下:
function alertHello(): void { //关于函数类型,在后面函数类型细说
alert('Hello');
}
‘null’和’undefined’
注意的点:
1)undefined
类型的变量只能被赋值为undefined
;null
类型的变量只能被赋值为null
。
2)undefined
和null
是所有类型的子类型。即:undefined
和null
类型的变量可以赋值给任何类型的变量
3)void
与前两者不同,void
类型的变量不能赋值其他类型
// 这样不会报错
let num: number = undefined;
// 这样也不会报错
let u: undefined;
let str: string = u;
let u: void;
let num: number = u;
// index.ts(2,5): error TS2322: Type 'void' is not assignable to type 'number'.
对象类型 (Object types)–接口
这是typescript的核心之一,在下面详说
任意值(Any)
若为普通类型,在赋值过程中改变类型是不允许的,但是any类型,则允许被赋值为任意类型
语法:
let varName: any;
varName = 'Tom';
varName = 3; //不会报错
PS:
1)在任意值上调用任何属性和方法都是允许的
2)声明一个变量为任意值后,对它的任何操作之后,返回的内容的类型都是任意值
3)变量如果在声明的时候未指定类型(前提是声明时不赋值,若赋值就会进行类型推论),那么它会被识别为任意值类型
let something;
something = 'seven';
something = 7;
something.setName('Tom');
等价于
let something: any;
something = 'seven';
something = 7;
something.setName('Tom');
类型推论
在声明时没有明确的指定类型的变量,会根据声明变量被赋值的类型推论变量的类型,一旦论定一种类型,就不允许再修改。不同于any
let str = 'seven'; //此处推论为string类型
str = 7;
// error TS2322: Type 'number' is not assignable to type 'string'.
事实上,它等价于:
let str: string = 'seven';
str = 7;
// error TS2322: Type 'number' is not assignable to type 'string'.
如果定义的时候没有赋值,不管之后有没有赋值,都会被推断成 any
类型而完全不被类型检查:
let str; //此时,str类型为any
str = 'seven';
str = 7;
联合类型 ·|·
通俗来说,|
就是类似于 或
,表示变量可以取几种类型中的一种
语法:
let varName: type1 | type2; //那么varName就可以取值的为类型type1或type2,但不允许除这两种类型之外的类型的值
PS:
1)变量不能取定义中之外的类型的值,比如上面不能赋值varName = true
,boolean
不在上面定义的类型
2)当还未确定变量属于哪一个类型时,变量只能访问定义中所有类型的共有属性或方法
3)联合类型的变量在被赋值时,会根据类型推论的规则推测出一个类型。有了确定的类型就可以调用相应的属性和方法了
eg:
function getLength(something: string | number): number {
return something.length;
}
上面报错,因为number类型的变量没有length属性。
下面的不会报错,因为toString()方法是string和number类型变量的共有方法
function getString(something: string | number): number {
return something.toString();
}
下面的代码编译出错,第二行的 myVar
被推断成了 string
,访问它的 length
属性不会报错。
而第四行的 myVar
被推断成了 number
,访问它的 length
属性时就报错了。
let myVar: string | number;
myVar = 'seven';
console.log(myVar.length); // 5
myVar = 7;
console.log(myVar.length); // 编译时报错
// error TS2339: Property 'length' does not exist on type 'number'.
对象类型–接口(interface)
在typeScript中,我们使用接口(interface)来定义对象的类型。面向对象中,接口是对行为的抽象,而具体如何行动需要在**类(classes)**中实现(implement)。ts中除了可用于对类的一部分行为进行抽象以外,也常用于对对象的形状进行描述。
对对象的形状描述语法:
interface InterfaceName {
readonly varName: type; //只读属性
varName1: type;
varName2?: type; //可选属性
[propName: string]: type; //任意属性
}
PS:
1)接口名一般首字母大写
2)任意属性的属性类型必须包含定义的其他变量的属性类型,即是说,其他属性的类型必须是任意属性类型的子集
定义变量语法:
let objName: InterfaceName {
//定义对应属性
}
PS:
1)若没有任意属性和可选属性,那么对象中的属性名和类型必须一致,而且属性不能多也不能少,即形状一致,且不允许添加未定义的属性
2)若存在只读属性,那么在对象创建时赋值之后,值就不能在被改变。即只读属性只能在创建对象时被赋值
3)可选属性就如同可选参数一样,可以有也可以没有。
eg:
//定义接口 -- 定义tom对象的类型
interface Person {
readonly id: number;
name: string;
sorce: number;
age?: number; //可选,这个例子中我们就没用这个属性
[propName: string]: string; //报错,number不是string的子集,可改为[propName: string]: any;
}
//创建tom对象
let tom: Person = {
id: 89757,
name: 4, //报错,类型不对
//报错,少了一个sorce属性
gender: 'male' //不报错,这是因为接口中定义了任意属性
};
tom.id = 9527; //报错,id为只读属性,除了创建对象时赋值,不允许再改变值
数组类型
数组类型定义方法有几种,比较灵活
「类型 + 方括号」表示法
语法:
let arr: number[] = [1,2,3];
ps:此处定义的数组类型是number,所以数组的项中不允许出现其他类型的值
数组泛型
语法:
let arr: Array<number> = [1,2,3];
ps:此处定义的数组类型是number,所以数组的项中不允许出现其他类型的值
数组的方法的参数也同样受数组定义的类型限制
arr.push("str"); //报错:arr是number类型,不能push其他类型
用接口表示数组
interface NumberArray {
[index: number]: number;
}
let arr: NumberArray = [1, 1, 2, 3, 5];
ps:此时创建的arr其实只是一个NumberArray
类型,不具有数组所具有的方法和属性;
console.log(arr.length); //报错,arr不具有数组的属性
arr.push(4); //报错,arr不具有数组的方法
类数组(不是数组类型)
类数组:
1)拥有length属性,其它属性(索引)为非负整数
2)不具有数组所具有的方法
2)常见的类数组都有自己的接口定义
如:IArguments
, NodeList
, HTMLCollection
等
eg:
function sum() {
let args: number[] = arguments;
//报错,error TS2322: Type 'IArguments' is not assignable to type 'number[]
}
正确的写法:
function sum() {
let args: IArguments = arguments;
}
any 数组任意类型
顾名思义:any类型的数组允许任何类型的项
let list: any[] = [1,'aa',{name: 'yang'}]
函数类型
函数定义
函数声明
语法:
function sum(x: number,x:number): number{
return x + y;
}
函数表达式
语法:
let sum: (x: number,y: number) => number = function(x: number,y: number): number {
return x + y;
}
接口定义函数的形状
语法:
interface Func {
(source: string, subString: string): boolean;
}
let mySearch: Func;
mySearch = function(source: string, subString: string) {
return source.search(subString) !== -1;
}
PS:
1)在没有可选参数和任意参数时,调用函数时的参数不能多也不能少
2)函数表达式 =>
区别与ES6 的箭头函数,不可混淆。此处=>
用来表示函数的定义,左边是输入类型,需要用括号括起来,右边是输出类型。
3)当函数没有返回值时,返回值类型为‘void’,此处可类比C语言
函数参数
可选参数
1)类似于接口中的可选属性,用**’?'表示可选参数
2)可选参数必须在必需参数的后面,即可选参数后不应该还有必需参数**
参数默认值
在 ES6 中,我们允许给函数的参数添加默认值,TypeScript 会将添加了默认值的参数识别为可选参数:
但不同的是,这儿的参数不受[可选参数必须接在必需参数后面]的限制了
function fullName(firstName: string = 'Tom', lastName: string) {
return firstName + ' ' + lastName;
}
let tomcat = fullName('Tom', 'Cat');
let cat = fullName(undefined, 'Cat');
若默认参数在后面,调用函数时未用到默认参数,就可以不写这个参数
function fullName(firstName: string, lastName: string = 'Cat') {
return firstName + ' ' + lastName;
}
let tomcat = fullName('Tom', 'Cat');
let tom = fullName('Tom');
剩余参数
ES6 中,可以使用 ...rest
的方式获取函数中的剩余参数(rest 参数):
PS:rest参数只能是在最后,毕竟是剩余的嘛。
eg:(我们知道items为数组类型)
function push(array: any[], ...items: any[]) {
items.forEach(function(item) {
array.push(item);
});
}
let a = [];
push(a, 1, 2, 3);
重载
重载允许一个函数接受不同数量或类型的参数时,做出不同的处理
可以类比C++的重载:
下面这个例子,是为了保证当我们不同类型的参数调用函数时,能得到正确类型的函数返回值
function reverse(x: number): number;
function reverse(x: string): string;
function reverse(x: number | string): number | string {
if (typeof x === 'number') {
return Number(x.toString().split('').reverse().join(''));
} else if (typeof x === 'string') {
return x.split('').reverse().join('');
}
}
PS:TypeScript 会优先从最前面的函数定义开始匹配,所以多个函数定义如果有包含关系,需要优先把精确的定义写在前面。
类型断言
类型断言:手动指定一个值的类
语法:
<类型>值
或
值 as 类型
我的理解:如同c语言中的强制类型转换,但又不一样,断言的类型必须是联合类型中存在的
当 TypeScript 不确定一个联合类型的变量到底是哪个类型的时候,我们只能访问此联合类型的所有类型里共有的属性或方法:而有时候,我们确实需要在还不确定类型的时候就访问其中一个类型的属性或方法,这时候我们就可以使用类型断言
eg:将一个联合类型的变量指定为一个更加具体的类型
function getLength(something: string | number): number {
//若这儿没有将somtthing断言成string类型,编译将会出错,因为something类型不确定,就只能调用string类型和number类型共有的属性和方法,而number没有length属性
if((<string>something).length) {
return (<string>something).toString().length;
}
}