如今前端技术层出不穷,es6
还没完全掌握,TypeScript
又来了,2020了,不会点TypeScript
都不好意思说自己是做前端的了。虽然技术层出不穷,但万变不离其宗,根据多年的开发经验,学习新技术其实也不是那么难,大多都差不多的,趁放假有时间,来了解下TypeScript
,等上班的时候就可以用上了。TypeScript
是 JavaScript
的一个超集,支持 ECMAScript 6
标准。其实跟swift
差不多,下面就来整理TypeScript
相关的知识点。
1.数据类型
TypeScript
的数据类型跟JavaScript
差不多,有数字,字符串,布尔值,数组等类型,还有结构体、元组、枚举类型等。
1.1.基础数据类型
定义数字,字符串,布尔值,数组等类型时,跟JavaScript
差不多,只是定义的语法稍微有一点点区别。如下所示:
let isLike: boolean = false;
let index: number = 1;
let firstName: string = 'haha';
let result: string = `my name is ${firstName}`;
let list:Array<number> = [1,2,3]
1.2.元组
元组是一个已知元素数量和类型的数组,各类型的元素不必相同,当访问一个已知索引的元素,会得到正确的类型,当访问一个越界的元素时,不会报错,会使用联合类型替代。
let array: [number, string] = [12, 'haha'];
console.log(array[0]);//12
console.log(array[1]);//haha
array[3] = 'ha';
console.log(array[3]);//ha
1.3.枚举
枚举类型是为一组数值赋予友好的名字。使用关键字enum
进行定义,如下所示:
enum Color { RED, GREEN, BLUE };
let color: Color = Color.RED;
console.log(color);//0
默认情况下是从0
开始的,也可以手动设置成员的数值,如下所示:
enum Color { RED = 1, GREEN, BLUE };
let color: Color = Color.RED;
console.log(color);//1
除了获取其成员的数值外,也可以通过数值来访问枚举的名称,如下所示:
enum Color { RED = 1, GREEN, BLUE };
console.log(Color[1]);//RED
1.4.Any
Any
代表任意类型的变量,它允许你在编译时可选择地包含或移除类型检查,比如将一个数组指定为Any
时,可以往数组中添加任意类型的数据。
let array: Array<any> = [1, 'haha', true, { a: 'aa' }];
console.log(array)
1.5.Void
Void
类型与Any
相关,表示没有任何类型,比如定义函数时,没有返回时,默认的类型为Void
类型。
function test() :void {
console.log('haha');
}
test();
1.5.Null 和 Undefined
TypeScript
里,undefined
和null
两者各自有自己的类型分别叫做undefined
和null
。 和 void
相似,它们的本身的类型用处不是很大。默认情况下null
和undefined
是所有类型的子类型。 就是说你可以把 null
和undefined
赋值给number
类型的变量。
1.6.Never
never
是表示那些永不存在的类型的值,一般用在抛出异常时,如下所示:
// 返回never的函数必须存在无法达到的终点
function error(message: string): never {
throw new Error(message);
}
1.6.Object
Object
表示那些除基本数据外的类型,也就是除number
,string
,boolean
,symbol
,null
或undefined
之外的类型。
1.7.类型断言
类型断言相当于类型转换,它没有运行时的影响,只是在编译阶段起作用。类型断言有两种方式,一种是会用<>
,一种是使用as
。如下所示:
let str: any = 'this is string';
let len: number = (<string>str).length;
var lenght: number = (str as string).length;
console.log(len);//14
console.log(lenght);//14
1.8泛型
泛型是一种创建可复用代码组件的工具,使用代码能提供代码的可复用性和通用性。用过泛型能有效增加类、类型和接口的使用能力。最常用的是在数组中限定类型,如下所示:
class Person {
age: number;
}
class Animal {
name: string;
}
let array: Array<Person> = [];
let person: Person = new Person();
let animal: Animal = new Animal();
array.push(person);
array.push(animal);//error
定义数组的时候,使用<>
定义了一个泛型,只能往数组中添加Person
的对象,如果往数组中添加Animal
的对象将报错。
泛型也是类型,泛型函数的类型与非泛型函数的类型没什么不同,只是有一个类型参数在最前面,像函数声明一样:
function identity<T>(arg: T): T {
return arg;
}
let myIdentity: <T>(arg: T) => T = identity;
2.接口
TypeScript
的核心之一是对值所具有的类型进行检查,在TypeScript
里,可以通过定义接口来设定一些类型规则。如下所示:
interface Person {
name:string
}
function test(person: Person) {
console.log(person.name);//haha
}
var obj = { name: 'haha', age: 10 }
test(obj);
如上代码所示,test
函数中有一个person
参数,并且类型为Person
,该参数做了限制,传给函数的参数必须要有 name
属性,否责会报错。
2.1可选属性
上面的代码定义的 name
属性是必须的,如果传给函数的参数没有name
属性会报错,可以通过可选属性来解除这种限制,可选属性使用?
来设置。如下所示:
interface Person {
name?: string
age?:number
}
function test(person: Person) {
console.log(person.name);//haha
}
test({age: 10 });
2.2只读属性
在定义变量的时候,可以使用readonly
来限制外部修改属性值,在创建的时候赋值后不能再修改。如下所示:
interface Person {
readonly name: string
age:number
}
var obj = { name: 'haha', age: 10 }
obj.name = 'hhhh'//error
2.3函数类型
接口除了描述带有普通属性的普通对象外,也可以描述函数类型。为了使用接口表示函数类型,需要给接口定义一个调用签名。它就像是一个只有参数列表和返回值类型的函数定义。参数列表里的每个参数都需要名字和类型。如下所示:
interface PersonInfo {
(name:string,age:number):string
}
定义好函数类型后,就可以像使用其它接口一样使用这个函数类型的接口,如下所示:
interface PersonInfo {
(name:string,age:number):string
}
let personInfo: PersonInfo;
personInfo = function (name: string, age: number): string {
var result: string;
result = `name:${name}
age:${age}`
return result;
}
console.log(personInfo('haha', 12));
2.4可索引类型
可索引类型具有一个 索引签名,它描述了对象索引的类型,还有相应的索引返回值类型。如下所示:
interface StringArray {
[index:number]:string
}
let array: StringArray = ['haha1', 'haha2']
console.log(array[1]);//haha2
TypeScript
支持两种索引签名,分别为数字和字符串。但是数字索引返回的类型必须是字符串索引返回类型的子类。这是因为用数字是索引时,javascript
会默认将数字转换为字符串后再去索引对象。
class Animal {
name: string;
}
class Dog extends Animal {
breed: string;
}
// 错误:使用数值型的字符串索引,有时会得到完全不同的Animal!
interface NotOkay {
[x: number]: Animal;
[x: string]: Dog;
}
2.5类类型
TypeScript
也能够使用接口来明确的强制一个类去符合某种契约。定义好接口后,使用implements
来实现接口,然后在类中添加接口的属性和方法,如下所示:
interface Person {
name: string,
eat();
}
class Student implements Person {
name: string;
eat() {
console.log(`${this.name}在吃东西`)
}
}
var stu = new Student();
stu.name = 'haha';
stu.eat();//haha在吃东西
2.6接口继承
接口也是可以继承,并且可以多重继承,可以很方便的将一个接口里的成员复制到另一个接口中,如下所示:
interface Shape {
color: string;
}
interface PenStroke {
penWidth: number;
}
interface Square extends Shape, PenStroke {
sideLength: number;
}
let square = <Square>{};
square.color = "blue";
square.sideLength = 10;
square.penWidth = 5.0;
3.类
TypeScript
中的类跟ES6
中的类差不多,只是定义属性的方式稍微有点差别,以下为 TypeScript
中定义的类。
class Animal {
name: string;
constructor(name: string) {
this.name = name;
}
eat() {
console.log('动物会吃东西');
}
}
class Dog extends Animal {
constructor(name: string) {
super(name);
}
eat() {
console.log(this.name +' 在吃东西');
}
}
class Cat extends Animal {
constructor(name) {
super(name)
}
eat() {
console.log(this.name +' 在吃东西');
}
}
let dog: Dog = new Dog('haha');
dog.eat();
let cat: Animal = new Cat('cat')
cat.eat();
.3.1变量修饰符
TypeScript
里可以使用public
,private
,protected
,readonly
修饰成员变量,默认为public
。
public
:默认的修饰符,外部可以访问。private
:当成员被标记成private
时,它就不能在声明它的类的外部访问。protected
:protected
修饰符与private
修饰符的行为很相似,但有一点不同,protected
成员在派生类中仍然可以访问。
-readonly
:readonly
关键字将属性设置为只读的。 只读属性必须在声明时或构造函数里被初始化。
3.2存取器
TypeScript
支持通过getters/setters
来截取对对象成员的访问。 它能帮助你有效的控制对对象成员的访问。
class Animal {
name: string;
private _fullName: string;
constructor(name: string) {
this.name = name;
}
set fullName(value) {
console.log('set fullname')
this._fullName = value;
}
get fullName() {
console.log('get fullname')
return this._fullName;
}
eat() {
console.log('动物会吃东西');
}
}
fullName
添加了get
和set
方法。
3.3 static
使用static
可以定义静态属性和静态方法。
class Animal {
static fullName: string;
static eat() {
console.log(Animal.fullName)
}
}
Animal.fullName = 'haha'
Animal.eat();//haha
4.类型推论
在TypeScript
里,在使用变量时可以推断出变量属性什么类型。
4.1自动推论:
在对属性和成员进行初始化时,可以进行自动推论,如下所示,将推断出变量x
的类型为number
类型。
let x = 12;
4.2最佳通用类型
当需要从几个表达式中推断类型的时候,会使用这些表达式的类型来推断出一个最合适的通用类型。如:
let x = [0, 1, null];
如果没有找到最佳通用类型,类型推断的结果为联合数组类型。
5.类型兼容性
TypeScript
里的类型兼容性是基于结构子类型的。 结构类型是一种只使用其成员来描述类型的方式。 它正好与名义(nominal)类型形成对比。比如下面的两个类,默认被当成同一个类型。
class Person {
name: string;
}
class Animal {
name: string;
}
这是因为在基于名义类型的类型系统中,数据类型的兼容性或等价性是通过明确的声明和/或类型的名称来决定的。这与结构性类型系统不同,它是基于类型的组成结构,且不要求明确地声明。
6.高级类型
6.1交叉类型
交叉类型是将多个类型合并成一个类型,它包含了所有类型的特性。如下所示:
class Person {
name: string;
}
class Animal {
name: string;
age: number;
run() {
console.log('running')
}
}
function extend<T, U>(first: T, second: U): T & U {
let result = <T & U>{};
for (let key in first) {
(<any>result)[key] = (<any>first)[key]
}
for (let key in second) {
(<any>result)[key] = (<any>second)[key];
}
return result;
}
var obj = extend(new Person(), new Animal());
obj.run();
6.2联合类型
联合类型表示一个值可以是几种类型之一,使用|
分隔每个类型。所以 number
| string
| boolean
表示一个值可以是 number
, string
,或 boolean
。如果一个值是联合类型,我们只能访问联合类型中所有类型的共有成员,如下所示:
class Person {
name: string;
eat() {
console.log('Person eat')
}
}
class Animal {
name: string;
age: number;
run() {
console.log('running')
}
eat() {
console.log('Animal eat')
}
}
function getObj(): Person | Animal{
return new Animal();
}
let obj1 = getObj();
obj1.eat();
obj1.run();//error
网友评论