interface
示例:
interface FullName {
firstName: string;
secondName: string;
}
function printName(name: FullName) {
console.log(name.firstName + '--' + name.secondName);
}
let obj = { // 编译器只会检查那些必需的属性是否存在,并且其类型是否匹配
firstName: 'xiao',
secondName: 'ming',
age: 12,
}
printName(obj)
在可选属性名字定义的后面加一个?
符号
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"});
原生js封装ajax:
interface Config {
type: string;
url: string;
data?: string;
dataType: string;
}
function ajax(config: Config) {
let xhr = new XMLHttpRequest();
xhr.open(config.type, config.url, true);
xhr.send(config.data);
xhr.onreadystatechange = function() {
if (xhr.readyState == 4 && xhr.status == 200) {
console.log('成功!');
if (config.dataType == 'json') {
console.log(JSON.parse(xhr.responseText));
} else {
console.log(xhr.responseText);
}
}
}
}
ajax({
type: 'get',
data: 'name=zhangsan',
url: 'http://a.itying.com/api/productlist',
dataType: 'json',
})
属性名前用 readonly
来指定只读属性
interface Point {
readonly x: number;
readonly y: number;
}
let p1: Point = { x: 10, y: 20 };
p1.x = 5; // error!
它就像是一个只有参数列表和返回值类型的函数定义。参数列表里的每个参数都需要名字和类型
interface SearchFunc {
(source: string, subString: string): boolean;
}
如何创建一个函数类型的变量
let mySearch: SearchFunc;
mySearch = function(source: string, subString: string) {
let result = source.search(subString);
return result > -1;
}
对于函数类型的类型检查来说,函数的参数名不需要与接口里定义的名字相匹配。重写上面的代码,函数的参数会逐个进行检查,要求对应位置上的参数类型是兼容的
let mySearch: SearchFunc;
mySearch = function(src: string, sub: string): boolean {
let result = src.search(sub);
return result > -1;
}
可索引类型具有一个 索引签名,它描述了对象索引的类型,还有相应的索引返回值类型
TypeScript支持两种索引签名:字符串和数字
定义:
interface StringDictionary {
[index: string]: string;
}
使用:
const myDict: StringDictionary = {
name: 'John',
greeting: 'Hello'
}
定义:
interface NumberDictionary {
[index: number]: string;
}
使用:
const myArray: NumberDictionary = {
10: 'ten',
20: 'twenty'
};
可以同时使用两种类型的索引,但是数字索引的返回值必须是字符串索引返回值类型的子类型, 这是因为当使用 number
来索引时,JavaScript会将它转换成string
然后再去索引对象。 也就是说用 100
(一个number
)去索引等同于使用"100"
(一个string
)去索引,因此两者需要保持一致。
class Animal {
name: string;
}
class Dog extends Animal {
breed: string;
}
// 错误:使用数值型的字符串索引,有时会得到完全不同的Animal!
interface NotOkay {
[x: number]: Animal;
[x: string]: Dog;
}
最后,你可以将索引签名设置为只读,这样就防止了给索引赋值
interface ReadonlyStringArray {
readonly [index: number]: string;
}
let myArray: ReadonlyStringArray = ["Alice", "Bob"];
myArray[2] = "Mallory"; // error! 因为索引签名是只读的
对类的约束
关键字: implements
// 定义类接口
interface ClockInterface {
currentTime: Date; // 属性
setTime(d: Date): void; // 方法
}
// 实现 ClockInterface 接口
class Clock implements ClockInterface {
currentTime: Date;
constructor() {
this.currentTime = new Date();
}
setTime(d: Date) {
this.currentTime = d;
}
}
使用 implements
只能约束类实例上的属性和方法,要约束构造函数和静态属性,需要这么写
interface CircleStatic {
new(radius: number): void;
pi: number;
}
const Circle: CircleStatic = class Circle {
radius: number;
static pi: 3.14; // 未定义静态属性 pi,会报错
constructor(radius: number) { // 如果constructor 入参类型(比如写成string)不对,会报错:
this.radius = radius;
}
}
和类一样,接口也可以相互继承,
关键字 extends
interface Shape {
color: string;
}
interface Square extends Shape {
length: number;
}
let square = <Square>{};
square.color = 'blue';
square.length = 10;
一个接口可以继承多个接口,创建出多个接口的合成接口
interface Shape {
color: string;
}
interface PenStroke {
width: number;
}
interface Square extends Shape, PenStroke {
length: number;
}
let square = <Square>{};
square.color = 'blue';
square.length = 10;
square.width = 20;
一个对象可以同时具有上面提到的多种类型。
一个例子就是,一个对象可以同时做为函数和对象使用,并带有额外的属性。
interface Counter {
(start: number): string;
interval: number;
reset(): void;
}
function getCounter(): Counter {
let counter = <Counter>function (start: number) { };
counter.interval = 123;
counter.reset = function () { };
return counter;
}
let c = getCounter();
c(10);
c.reset();
c.interval = 5.0;
当接口继承了一个类类型时,它会继承类的成员但不包括其实现
class Control {
private state: any;
}
// SelectableControl包含了Control的所有成员,包括私有成员state
interface SelectableControl extends Control {
select(): void;
}
class Button extends Control implements SelectableControl {
select() {}
}
class TextBox extends Control {
select() {};
}
// Button和TextBox类是SelectableControl的子类(因为它们都继承自Control并有select方法)
// 错误:“Image”类型缺少“state”属性。Image并不是SelectableControl的子类
class Image1 implements SelectableControl {
select() {};
}