typescript接口

typescript的核心原则之一就是对值所具有的结构进行类型检查。被称作,‘鸭式变型法’或“结构性子类型化”

接口初探

  1. function fun(first: { label: string }, second: {value:number},third:number,fourth?:number) {
  2. }
  3. fun({ label: '1' }, {value : 1},1)
  4. js=>
  5. function fun(first, second, third, fourth) {
  6. }
  7. fun({ label: '1' }, { value: 1 }, 1);

可选类型

  1. interface SquareConfig{
  2. color?:string;
  3. width?:number;
  4. }

两个好处。1.可以对可能存在的属性进行预定义。2.可以捕获引用不存在的属性时的错误。

只读属性

  1. interface Point{
  2. readonly x : number;
  3. readonly y : number;
  4. }
  1. let a : number[]=[1,2,3,4];
  2. let ro: ReadonlyArray<number>=a;
  3. ro[1]=1 //error!
  4. ro.push(1) //error
  5. a=po//error

typescript具有ReadonlyArray类型,与Array相似,去掉了所有的可变方法,可以确保数组创建后不被更改。把ReadonlyArray复制到普通数组需要借助于类型断言

  1. a = po as number[];

readonly VS const

作为变量用const,属性用readonly

额外的属性检查

错误的使用

  1. interface SquareConfig {
  2. color?: string;
  3. width?: number;
  4. }
  5. function createSquare(config: SquareConfig): { color: string; area: number } {
  6. // ...
  7. }
  8. let mySquare = createSquare({ colour: "red", width: 100 });

解决方法:
1.断言 let mySquare = createSquare({ width: 100, opacity: 0.5 } as SquareConfig);
2.字符串索引签名

  1. interface SquareConfig {
  2. color?: string;
  3. width?: number;
  4. [propName: string]: any;
  5. }

注意:不应该去绕开这些检查,应该去修改接口定义

函数类型

描述函数类型

  1. interface SearchFunc {
  2. (source: string, subString: string): boolean;
  3. }
  4. let mySearch: SearchFunc;
  5. mySearch = function(source: string, subString: string) {
  6. let result = source.search(subString);
  7. return result > -1;
  8. }
  9. // 函数类型的类型检查来说,函数的参数名不需要与接口里定义的名字相匹配。
  10. let mySearch: SearchFunc;
  11. mySearch = function(src: string, sub: string): boolean {
  12. let result = src.search(sub);
  13. return result > -1;
  14. }
  15. // 如果你不想指定类型,TypeScript的类型系统会推断出参数类型,因为函数直接赋值给了 SearchFunc类型变
  16. let mySearch: SearchFunc;
  17. mySearch = function(src, sub) {
  18. let result = src.search(sub);
  19. return result > -1;
  20. }

可索引的类型

与使用接口描述函数类型差不多,也可以使用接口描述能够“通过索引得到的类型”,比如ageMap[“detail”]。

  1. interface StringArray{
  2. [index:number]:string;
  3. }
  4. let myArray:StringArray;
  5. myArray=["Bob]
  6. let myStr:string =myArray[0]

定义了StringArray接口,具有索引标签,索引签名表示了当用number去索引StringArray时会得到string类型的返回值。

TypeScript支持两种索引签名:字符串和数字。可以同时使用两种类型的索引,数字索引返回值必须是字符串索引返回值的子类型。因为使用number来索引时,JavaScript会将它转换成string然后再去索引对象。所以需要保持一致。

  1. class Animal {
  2. name: string;
  3. }
  4. class Dog extends Animal {
  5. breed: string;
  6. }
  7. // 错误:使用数值型的字符串索引,有时会得到完全不同的Animal!
  8. interface NotOkay {
  9. [x: number]: Animal;
  10. [x: string]: Dog;
  11. }
  12. interface NumberDictionary {
  13. [index: string]: number;
  14. length: number; // 可以,length是number类型
  15. name: string // 错误,`name`的类型与索引类型返回值的类型不匹配
  16. }
  17. //可以将索引签名设置为只读,这样就防止了给索引赋值:
  18. interface ReadonlyStringArray {
  19. readonly [index: number]: string;
  20. }
  21. let myArray: ReadonlyStringArray = ["Alice", "Bob"];
  22. myArray[2] = "Mallory"; // error!

类类型

实现接口

作用与Java类似

  1. interface ClockInterface {
  2. currentTime: Date;
  3. setTime(d: Date);
  4. }
  5. class Clock implements ClockInterface {
  6. currentTime: Date;
  7. setTime(d: Date) {
  8. this.currentTime = d;
  9. }
  10. constructor(h: number, m: number) { }
  11. }

接口描述了公共部分,不会检验类是否具有某些私有成员。

类静态部分与实例部分的区别。

当一个类实现了一个接口时,只对其实例部分进行类型检查

#

继承接口

和类一样,接口可以相互继承,能够从一个接口里复制成员到另一个接口里,可以灵活地将接口分割到可重用的模块里。

  1. // 可以继承多个接口
  2. interface Shape {
  3. color: string;
  4. }
  5. interface PenStroke {
  6. penWidth: number;
  7. }
  8. interface Square extends Shape, PenStroke {
  9. sideLength: number;
  10. }
  11. let square = <Square>{};
  12. square.color = "blue";
  13. square.sideLength = 10;
  14. square.penWidth = 5.0;

混合类型

由于JavaScript的动态灵活特点,希望一个对象可以同时具有多种类型

  1. interface Counter {
  2. (start: number): string;
  3. interval: number;
  4. reset(): void;
  5. }
  6. function getCounter(): Counter {
  7. let counter = <Counter>function (start: number) { };
  8. counter.interval = 123;
  9. counter.reset = function () { };
  10. return counter;
  11. }
  12. let c = getCounter();
  13. c(10);
  14. c.reset();
  15. c.interval = 5.0;

接口继承类

当接口继承了一个类时,会继承类的成员但不包括类的实现。接口会继承到类的private和protected成员。例如当接口继承了含有私有或保护成员的类时,这个接口的类型只能被这个类或其子类所实现。

  1. class Control {
  2. private state: any;
  3. }
  4. interface SelectableControl extends Control {
  5. select(): void;
  6. }
  7. class Button extends Control implements SelectableControl {
  8. select() { }
  9. }
  10. class TextBox extends Control {
  11. select() { }
  12. }
  13. // 错误:“Image”类型缺少“state”属性。
  14. class Image implements SelectableControl {
  15. select() { }
  16. }
  17. class Location {
  18. }