- 接口的可选属性: ?表示 不一定会存在的属性
interface SquareConfig {
color?: string;
width?: number;
}
function createSquare(config: SquareConfig): {color: string; area: number} {
let newSquare = {color: "white", area: 100};
if (config.color) {
newSquare.color = config.color;
}
if (config.width) {
newSquare.area = config.width * config.width;
}
return newSquare;
}
let mySquare = createSquare({color: "black"});
- 只读属性 :readonly
这些对象属性只能在对象刚刚创建的时候修改其值
interface Point {
readonly x: number;
readonly y: number;
}
/*
最简单判断该用readonly还是const的方法是看
要把它做为变量使用还是做为一个属性。
做为变量使用的话用 const,若做为属性则使用readonly。
*/
相似地,TypeScript具有ReadonlyArray < T > 类型,把所有可变方法去掉了,因此可以确保数组创建后再也不能被修改:
- 使用接口描述函数类型:调用签名
要写入参数,参数类型,输出,输出类型
interface SearchFunc {
(source: string, subString: string): boolean;
}
let mySearch: SearchFunc;
mySearch = function(source: string, subString: string) {
let result = source.search(subString);
return result > -1;
}
- 索引签名
描述对象索引时候的,对象索引类型和索引返回值
interface StringArray {
[index: number]: string;
}
let myArray: StringArray;
myArray = ["Bob", "Fred"];
let myStr: string = myArray[0];
注意:同时存在字符串索引和数字索引时,底层是会将数字索引转化为字符串再索引的(这一点和JS一致),所以要让数字索引的结果类型是字符串索引结果类型的子类型,不然可能会出错。
class Animal {
name: string;
}
class Dog extends Animal {
breed: string;
}
// 错误:使用数值型的字符串索引,有时会得到完全不同的Animal!
interface NotOkay {
[x: number]: Animal;
[x: string]: Dog;
}
应用:
//写一个dictionary类型
interface NumberDictionary {
[index: string]: number;
length: number; // 可以,length是number类型
name: string // 错误,`name`的类型与索引类型返回值的类型不匹配
}
//防止使用索引赋值
interface ReadonlyStringArray {
readonly [index: number]: string;
}
let myArray: ReadonlyStringArray = ["Alice", "Bob"];
myArray[2] = "Mallory"; // error!
- private和protected对于兼容的影响:
TypeScript使用的是结构性类型系统。 当我们比较两种不同的类型时,并不在乎它们从何处而来,如果所有成员的类型都是兼容的,我们就认为它们的类型是兼容的。
然而,当我们比较带有 private或 protected成员的类型的时候,情况就不同了。 如果其中一个类型里包含一个 private成员,那么只有当另外一个类型中也存在这样一个 private成员, 并且它们都是来自同一处声明时,我们才认为这两个类型是兼容的。 对于 protected成员也使用这个规则。
一句话 要严格对应,且同源。
class Animal {
private name: string;
constructor(theName: string) { this.name = theName; }
}
class Rhino extends Animal {
constructor() { super("Rhino"); }
}
class Employee {
private name: string;
constructor(theName: string) { this.name = theName; }
}
let animal = new Animal("Goat");
let rhino = new Rhino();
let employee = new Employee("Bob");
animal = rhino;
animal = employee; // 错误: Animal 与 Employee 不兼容.
因为 Animal和 Rhino共享了来自 Animal里的私有成员定义 private name: string,因此它们是兼容的。 然而 Employee却不是这样。当把 Employee赋值给 Animal的时候,得到一个错误,说它们的类型不兼容。 尽管 Employee里也有一个私有成员 name,但它明显不是 Animal里面定义的那个。
- 把类当做接口使用
如上一节里所讲的,类定义会创建两个东西:类的实例类型和一个构造函数。 因为类可以创建出类型,所以你能够在允许使用接口的地方使用类。
class Point {
x: number;
y: number;
}
interface Point3d extends Point {
z: number;
}
let point3d: Point3d = {x: 1, y: 2, z: 3};