二. 进阶
1. 类型推断:
如果没有明确的指定类型,那么 TypeScript 会按照类型推论(Type Inference)的规定推断出一个类型。
如果定义的时候没有赋值,不论之后有没有赋值,都会被推断成 any 类型而齐全不被类型查看:
let myFavoriteNumber;
myFavoriteNumber = 'seven';
myFavoriteNumber = 7;
2. 联结类型:
联结类型(Union Types)示意取值能够为多种类型中的一种,应用 ” | “ 分隔每个类型。联结类型的变量在被赋值的时候,会依据类型推论的规定推断出一个类型。
let myFavoriteNumber: string | number;
myFavoriteNumber = 'seven';
myFavoriteNumber = 7;
myFavoriteNumber = true;//index.ts(2,1): error TS2322: Type 'boolean' is not assignable to type 'string | number'.
3. 类型别名:
类型别名用来给一个类型起个新名字。应用 type 能够创立类型别名,类型别名罕用于联结类型。
type Name = string;
type NameResolver = () => string;
type NameOrResolver = Name | NameResolver;
function getName(n: NameOrResolver): Name {if (typeof n === 'string') {return n;} else {return n();
}
}
当 TypeScript 不确定一个联结类型的变量到底是哪个类型的时候,咱们 只能拜访此联结类型的所有类型里共有的属性或办法。
4. 字符串字面量类型:
字符串字面量类型用来束缚取值只能是某几个字符串中的一个。咱们应用 type 定了一个字符串字面量类型 EventNames,它只能取三种字符串中的一种。留神,类型别名与字符串字面量类型都是应用 type 进行定义。
type EventNames = 'click' | 'scroll' | 'mousemove';
function handleEvent(ele: Element, event: EventNames) {// do something}
handleEvent(document.getElementById('hello'), 'scroll'); // 没问题
handleEvent(document.getElementById('world'), 'dblclick'); // 报错,event 不能为 'dblclick'
5. 接口:
在面向对象语言中,接口(Interfaces)是一个很重要的概念,它是对行为的形象,而具体如何口头须要由类(classes)去实现(implement)。TypeScript 中的接口是一个非常灵活的概念,除了可用于对类的一部分行为进行形象以外,也罕用于对「对象的形态(Shape)」进行形容。
interface Person {
name: string;
age: number;
}
let tom: Person = {
name: 'Tom',
age: 25
};
let tom: Person = {name: 'Tom'};
// index.ts(6,5): error TS2322: Type '{name: string;}' is not assignable to type 'Person'.
let tom: Person = {
name: 'Tom',
age: 25,
gender: 'male'
};
// index.ts(9,5): error TS2322: Type '{name: string; age: number; gender: string;}' is not assignable to type 'Person'.
可见,赋值的时候,变量的形态必须和接口的形态保持一致。
⑴可选属性:
该属性可选,应用? 标记,但依然不容许增加未定义的属性。
interface Person {
name: string;
age?: number;
}
let tom: Person = {name: 'Tom'};
let tom: Person = {
name: 'Tom',
age: 25,
gender: 'male'
};// 报错,依然不容许增加未定义的属性
⑵任意属性:
应用 [propName: string] 定义了任意属性取 string 类型的值。一旦定义了任意属性,那么确定属性和可选属性的类型都必须是它的类型的子集。
interface Person {
name: string;
age?: number;
[propName: string]: string;
// 改为[propName: string]: any; 即正确
// 也能够改为联结类型[propName: string]: string | number;
}
let tom: Person = {
name: 'Tom',
age: 25,
gender: 'male'
};
// 任意属性的值容许是 string,然而可选属性 age 的值却是 number,number 不是 string 的子属性,所以报错了
⑶只读属性:
能够用 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;
// index.ts(14,5): error TS2540: Cannot assign to 'id' because it is a constant or a read-only property.
6. 类:
⑴public private 和 protected:
TypeScript 能够应用三种拜访修饰符(Access Modifiers),别离是 public
、private
和 protected
。
public
润饰的属性或办法是私有的,能够在任何中央被拜访到,默认所有的属性和办法都是public
的。private
润饰的属性或办法是公有的,不能在申明它的类的内部拜访。protected
润饰的属性或办法是受爱护的,它和 private 相似,区别是它在子类中也是容许被拜访的。
注:
①应用 private
润饰的属性或办法是无奈直接存取的,在子类中也是不容许拜访的;而如果是用 protected
润饰,则容许在子类中拜访。须要留神的是,TypeScript 编译之后的代码中,并没有限度 private
属性在内部的可拜访性。
class Animal {
public name;
private type;
public constructor(name, type) {
this.name = name;
this.type = type;
}
}
let a = new Animal('Jack', 'human');
console.log(a.name); // Jack
a.name = 'Tom';
console.log(a.name); // Tom
a.type = 'monkey';
console.log(a.type); // index.ts(9,13): error TS2341: Property 'type' is private and only accessible within class 'Animal'.
②当构造函数 constructor
润饰为 private
时,该类不容许被继承或者实例化;当构造函数 constructor
润饰为 protected
时,该类只容许被继承。
⑵参数属性和 readonly:
修饰符和 readonly
还能够应用在结构函数参数中,等同于类中定义该属性同时给该属性赋值,使代码更简洁。只读属性关键字 readonly
,只容许呈现在属性申明或索引签名或构造函数中。留神如果 readonly
和其余拜访修饰符同时存在的话,须要写在其前面。
class Animal {
// public name: string;
public constructor(public name) {//public constructor(public readonly name) {// this.name = name;}
}
class Animal {
readonly name;
public constructor(name) {this.name = name;}
}
let a = new Animal('Jack');
console.log(a.name); // Jack
a.name = 'Tom';
// index.ts(10,3): TS2540: Cannot assign to 'name' because it is a read-only property.
⑶抽象类:
abstract
用于定义抽象类和其中的形象办法。首先,抽象类是不容许被实例化的,其次,抽象类中的形象办法必须被子类实现。即便是形象办法,TypeScript
的编译后果中,依然会存在这个类。
abstract class Animal {
public name;
public constructor(name) {this.name = name;}
public abstract sayHi();}
class Cat extends Animal {public sayHi() {// 须要实现形象办法
console.log(`Meow, My name is ${this.name}`);
}
}
let a = new Animal('Jack');// 不能实例化抽象类
//index.ts(9,11): error TS2511: Cannot create an instance of the abstract class 'Animal'.
let cat = new Cat('Tom');// 只能实例化子类
⑷类的类型:
给类加上 TypeScript 的类型很简略,与接口相似:
class Animal {
name: string;
constructor(name: string) {this.name = name;}
sayHi(): string {return `My name is ${this.name}`;
}
}
let a: Animal = new Animal('Jack');
console.log(a.sayHi()); // My name is Jack