接口
在JavaScript中没有这个概念。
接口初探
function printLabel(labelledObj: { label: string }) { console.log(labelledObj.label);}// label为传入对象参数必有的一个属性let myObj = { size: 10, label: "Size 10 Object" };printLabel(myObj);
下面利用接口重写例子
//个人理解为将传入参数要求提出来,看起来更加清晰interface LabelledValue { label: string;}function printLabel(labelledObj: LabelledValue) { console.log(labelledObj.label)}let myObj = { size: 10, label: "Size 10 Object" };printLabel(myObj);
还有一点值得提的是,类型检查器不会去检查属性的顺序,只要相应的属性存在并且类型也是对的就可以。
可选属性
接口里的属性不全都是必需的。
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"});
只读属性
只读属性创建后不能再次修改。
interface Point { readonly x: number; readonly y: number;}let p1: Point = { x: 10, y: 20 };p1.x = 5; // error!
下面的代码可以让ro数组创建后再也无法改变
let a: number[] = [1, 2, 3, 4];let ro: ReadonlyArray<number> = a;ro[0] = 12; // error!ro.push(5); // error!ro.length = 100; // error!a = ro; // error!a = ro as number[]; //right
readonly
VS const
官方解说:最简单判断该用readonly
还是const
的方法是看要把它做为变量使用还是做为一个属性。 做为变量使用的话用 const
,若做为属性则使用readonly
。
额外的属性检查
可以漏写部分属性,但不能多写属性或者错写属性,即如果传入的对象中含有目标类型不存在的属性,TS 额外的属性检查机制会进行报错。
官方提供了绕开 TS 的额外属性检查的办法:
// 1. 使用类型断言let mySquare = createSquare({ width: 100, opacity: 0.5 } as SquareConfig);// 2. 声明接口时来一个任意类型,此时这个声明为该接口的对象,可以有任意数量、任意类型、只要名字不是 color 或 width 的属性interface SquareConfig { color?: string; width?: number; [propName: string]: any;}// 3. 更简单,只要把对象赋值到另一个变量上(抽离出来)即可:let squareOptions = { colour: "red", width: 100 };let mySquare = createSquare(squareOptions);
个人感觉不要使用,毕竟这个是TS来帮我们检查BUG的。
函数类型
使用接口表示函数类型
//像是一个只有参数列表和返回值类型的函数定义。参数列表里的每个参数都需要名字和类型。interface SearchFunc { (source:string, subString:string):boolean}
使用方法
let mySearch:SearchFunc = function(src:string,sub:string){ let result = source.search(sub) return result > -1}
当然可以省略部分代码
let mySearch:SearchFunc = function(src,sub){ let result = source.search(sub) return result > -1}
可索引类型
interface StringArray { [index: number]: string;}let myArray: StringArray;myArray = ["Bob", "Fred"];let myStr: string = myArray[0];
这个索引签名表示了当用 number
去索引StringArray
时会得到string
类型的返回值。
class Animal { name: string;}class Dog extends Animal { breed: string;}interface NotOkay { [x: number]: Animal;//此处错误 [x: string]: Dog;}
因为当使用 number
来索引时,JavaScript会将它转换成string
然后再去索引对象。 也就是说用 100
(一个number
)去索引等同于使用"100"
(一个string
)去索引。
记住一句话:数字类型索引的返回值必须是字符串类型索引返回值的子类型。这里Animal
是Dog
的父类型,所以错误。
此外,字符串索引签名能够很好的描述dictionary模式,并且它们也会确保所有属性与其返回值类型相匹配。
如:
interface NumberDictionary { [index: string]: number; length: number; // 可以,length是number类型 name: string // 错误,`name`的类型与索引类型返回值的类型不匹配}//这里一知半解不太明白是什么意思
最后你还可以给索引签名设置为只读,防止了给索引赋值:
interface ReadonlyStringArray { readonly [index: number]: string;}
类类型
这一部分等看了TS中的类以后再回头来看
继承接口
interface Shape { color: string;}interface Square extends Shape { sideLength: number;}let square = <Square>{};square.color = "blue";square.sideLength = 10;
这样square
的2个参数都要受限制了
一个接口可以继承多个接口,创建出多个接口的合成接口。
interface Shape { color: string;}interface PenStroke { penWidth: number;}interface Square extends Shape, PenStroke { sideLength: number;}
混合类型
这个也留着以后回头来看
接口继承类
同上