TypeScript是JavaScript的一个超集,主要提供了类型系统和对ES6的支持,由Microsoft开发。
基础
原始数据类型
1)布尔值: let isDone: boolean = false;
2)数值:
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
3)字符串:
let name:string = 'zhao';
let age:number = 22; //模板字符串
let sentence: string = `Hello,my name is ${name} I'll be ${myAge + 1} years old next month.`
4)空值 JS中没有空值的概念,TS中,使用void表示没有任何返回值的函数
function alertName(): void{
alert('My name is zhao');
}
5)Null和Undefined let u: undefined = undefined; let n: null = null
任意值
Any可以用来表示允许赋值为任意类型,如果是一个普通类型,在赋值过程中改变类型是不被允许的,但如果是any类型,则允许被赋值为任意类型。
在any上访问任何属性都是被允许的,也可以调用任何方法。可以认为,声明一个变量为任意值后,对他的任何操作,返回的内容的类型都是任意值。
变量在声明时,未指定其类型,那么它会被识别为任意值类型。
类型推理
TS会在,没有明确的指定类型时推测出一个类型,这就是类型推论。如果定义时没有赋值,不管之后有没有赋值,都会被推断为any类型而完全不被类型检查。
//以下代码虽然没有指定类型,但是会在编译的时候报错:
function alertName(): void{
alert('My name is zhao');
}
//事实上,它等价于:
let myFavoriteNumber: string = 'seven';
myFavoriteNumber = 7; // index.ts(2,1): error TS2322: Type 'number' is not assignable to type 'string'.
联合类型
联合类型表示取值可以为多种类型中的一种。使用 | 分隔每个类型。
let myFavoriteNumber: string | number;
myFavoriteNumber = 'seven';
myFavoriteNumber = 7;
let myFavoriteNumber: string | number;
myFavoriteNumber = true;
// Type 'boolean' is not assignable to type 'string | number'.
//Type 'boolean' is not assignable to type 'number'.
当TS不确定一个联合类型的变量到底是哪个类型的时候,会访问此联合类型的所有类型里共有的属性或方法。
function getLength(something: string | number): number {
return something.length;
}
// error TS2339: Property 'length' does not exist on type 'string | number'.
// Property 'length' does not exist on type 'number'.
上例中,length 不是 string 和 number 的共有属性,所以会报错。
访问 string 和 number 的共有属性是没问题的:
function getString(something: string | number): string {
return something.toString();
}
对象的类型——接口
在TS中,我们使用接口(Interfaces)来定义对象的类型。
接口:在面向对象中,接口(Interfaces)是对行为的抽象,具体如何行动要由类(classes)去实现(implement)。
interface Person{ name: string; age: number; }
let zhao: Person = { name: 'zhao', age: 22 }
定义的变量比接口少了一些属性是不被允许的,多一些属性也是不被允许的。赋值时,变量的形状必须和接口的形状保持一致。
有时候我们希望不要完全匹配一个形状,可以使用可选属性
interface Person {
name: string;
age?: number;
}
//age可以存在也可以不存在,此时仍然不允许添加未定义的属性。
有时候我们希望一个接口允许有任意的属性,可以使用任意属性
interface Person {
name: string;
age?: number;
[propName: string]: any;
} //[propName: string]定义了任意属性取string类型的值
一旦定义了任意属性,那么确定属性和可选属性的类型都必须是它的类型的子集:
interface Person {
name: string;
age?: number;
[propName: string]: string;
}
let tom: Person = {
name: 'Tom',
age: 25,
gender: 'male'
};
此时会报错,因为任意属性的值允许是string,但可选属性age的值却是number,number不是string的子属性,所以报错。
一个接口中只能定义一个任意属性,如果接口中有多个类型的属性,则可以在任意属性中使用联合类型。
interface Person {
name: string;
age?: number;
[propName: string]: string | number;
}
let tom: Person = {
name: 'Tom',
age: 25,
gender: 'male'
};
只读属性
有时候我们希望对象中的一些字段只能在创建的时候被赋值,那么可以用 readonly 定义只读属性:
interface Person {
readonly id: number;
name: string;
age?: number;
[propName: string]: any;
}
let tom: Person = {
id: 89757,
name: 'Tom',
gender: 'male'
};
tom.id = 9527; //报错
注意: 只读的约束存在于第一次给对象赋值的时候,而不是第一次给只读属性赋值的时候
数组的类型
1)[类型+方括号]表示法: let arr:number[] = [1,2,3,4,5] 数组的项中不允许出现除number外其他的类型。
2)数组泛型:ler arr:Array<number> = [1,2,3,4,5]
3)用接口表示数组:
interface NumberArray {
[index: number]: number; //只要索引的类型是数字时,那么值的类型必须是数字。
}
let arr : NumberArray = [1,2,3,4,5]
4)类数组:
function sum() {
let arg: number[] = arguments;
}
上例中,arguments 实际上是一个类数组,不能用普通的数组的方式来描述,而应该用接口:
function sum() {
let args: {
[index: number]: number;
length: number;
callee: Function;
} = arguments;
}
any表示数组中允许出现任意类型:
let list:any[] = ['zhao',25,{obj:'111}];
函数的类型
函数声明
JS中:定义函数的方式有函数声明和函数表达式
TS中:一个函数有输入和输出,需要在TS中对其进行约束
1)函数声明
function sum(x:number,y:number): number{
return x+y;
} //输入多余的或少于要求的参数时不被允许的
2)函数表达式
let mySum :(x:nubmber,y:number) => number = function(x:number, y:number):number{
return x+y;
}
在TS的类型定义中,=>用来表示函数定义,左边是输入类型,需要用括号括起来,右边是输出类型。(返回类型为number)
3)用接口定义函数的形状
interface SearchFunc { (source: string, subString: string): boolean; }
let mySearch: SearchFunc;
mySearch = function(source: string, subString: string) {
return source.search(subString) !== -1;
}
4)对于联合类型的函数,可以采用重载的方式
function getVal(value:number):number;
function getVal(value:string):string;
function getVal(value:string|number):string|number{
return value
}
let a:string = getVal('zhao') //输入是string,输出也是string
let b:number = getVal(123) //输入是number,输出也是number
类型断言
可以用来手动指定一个值的类型
语法:值 as 类型 或 <类型>值
f
unction getAssert(name:string | number){
//return (<string>name).length //将name断言为string类型,jsx中不能用
return (name as string).string //将name断言为string类型
}
只能转换联合类型中存在的类型
类型别名
可以给一个类型起一个新名字
type strType = string|nubmer|boolean;
let str:strType = "10"
str = 10
str = true
接口也可以使用类型别名
interface muchType1{ name: string }
interface muchType2{ age:number }
type muchType = muchType1 | muchType2
let obj: muchType = {name:'zhao'}
let obj1: muchType = {age:22}
let obj2: muchType = {name:'li',age:20}
限制字符串的选择
type sex = "男"|"女"
function getSex(s:sex):string{
return s
}
let a = getSex("男") //男
枚举
枚举(Enum)类型用于取值被限定在一定范围内的场景。枚举成员会被赋值为从0开始递增的数字,同时也会被枚举值到枚举名进行反向映射
enum Days{
Sun, Mon, Tue, Wed, Thu, Fri, Sta
}
console.log(Days.Sun) //0
console.log(Days.Sat) //6
console.log(Days[0]) //'Sun'
类修饰符
public修饰的属性或者方法是共有的,可以在任何地方被访问到,默认所有的属性或者方法都是public的
private修饰的属性或者方法是私有的,不能在声明它的类外面访问
protected修饰的属性或方法是受保护的,它和private类似
class Person{
private sex="男"
protected marraied = false
name = "张"
age = 18
say(){
console.log('my name is'+this.name,'my age is'+this.age)
}
}
var p = new Person()
p.say()
console.log(p.name) //当一个类成员变量没有修饰的时候,外界是可以进行访问的,默认public修饰 console.log(p.sex)//无法访问
//父类protected的属性在子类里可以拿到,外面不行
class Child extends Person{
callParent(){
super.say() //调父类方法
console.log(super.marraied)//可以访问
}
static test(){
//静态方法中不可以使用this console.log('test')
}
}
var c = new Child()
c.callParent()
console.log(c.age) //子类继承父类,可以访问到父类公开的属性/方法
console.log(c.sex) //无法访问
console.log(c.marraied) //无法访问
console.log(c.say())
console.log(Child.callParent()) //报错,无法直接通过类调取该方法
console.log(Child.test()) //可以
console.log(c.test()) //无法访问
//总结:静态方法是属于类的
泛型
是指定义函数、接口或类的时候,不预先指定具体类型,而在使用的时候再指定类型的一种特性。
function creatArray(length:number,value:any):Array<any>{
let arr = []
for(let i =0;i<length;i++){
arr[i] = value
}
return arr;
}
createArray(3,1) //[1,1,1]
//使用泛型改造上面代码
function creatArray<T>(length:number,value:T):Array<T>{
let arr = []
for(let i =0;i<length;i++){
arr[i] = value
}
return arr;
}
let strArr:string[] = createArray<string>(3,'1')
let numArr:number[] = createArray(3,1)
接口中采用泛型
interface ICreat{ <T>(name:string,value:T):Array<T> }
let func:ICreate;
func = function<T>(name:string,value:T):Array<T>{
return []
}
let strArr:string[] = func('zhao','student')
let strArr2:number[] = func('zhao',18)