In TypeScript, interfaces are used as constraints. When compiled into JavaScript, all interfaces will be erased because there is no concept of interfaces in JavaScript.
Let’s take a look at a simple example:
function printLabel(labelledObj: { label: string }) { console.log(labelledObj.label); } var myObj = { size: 10, label: "Size 10 Object" }; printLabel(myObj);
Then in this method, the type of labeledObj is {label: string}, which may seem a bit complicated, but if we look at the declaration of myObj below, we will know that this is a declaration with a size attribute (value is 10) and an object with a label attribute (value "Size 10 Object"). Therefore, the type of the method parameter labeledObj is {label: string}, which means that the parameter has a label attribute of type string.
However, written like this, this method still seems a bit confusing. Then you can use an interface to define the parameter type of this method.
interface LabelledValue { label: string; } function printLabel(labelledObj: LabelledValue) { console.log(labelledObj.label); } var myObj = { size: 10, label: "Size 10 Object" }; printLabel(myObj);
Optional attributes
Sometimes, we don’t need the attribute to exist, so we can use the optional attribute to define it.
interface SquareConfig { color?: string; width?: number; } function createSquare(config: SquareConfig): { color: string; area: number } { var newSquare = { color: "white", area: 100 }; if (config.color) { newSquare.color = config.color; } if (config.width) { newSquare.area = config.width * config.width; } return newSquare; } var mySquare = createSquare({ color: "black" });
Then we pass in an object that implements a SquareConfig interface into the createSquare method.
Since it is completely dispensable, why do we need to define it? Defining optional properties has two advantages over not defining them at all. 1. If there are attributes, the type can be constrained, which is very critical; 2. You can get intelligent syntax prompts. If you mistakenly write color in the method body as collor, then the compilation will not pass.
Method Type
In JavaScript, the method function is a basic type. In object-oriented thinking, the implementation of interfaces is accomplished by classes. As a type, can function implement interfaces? The answer is yes.
In TypeScript, we can use interfaces to constrain method signatures.
interface SearchFunc { (source: string, subString: string): boolean; } var mySearch: SearchFunc; mySearch = function(source: string, subString: string) { var result = source.search(subString); if (result == -1) { return false; } else { return true; } }
In the above code, we define an interface, which constrains the signature of a method. This method has two string parameters and returns a Boolean value. In the second piece of code we declare the implementation of this interface.
It should be noted that the compiler only checks whether the type is correct (parameter type, return value type), so we can change the parameter name to something else.
var mySearch: SearchFunc; mySearch = function(src: string, sub: string) { var result = src.search(sub); if (result == -1) { return false; } else { return true; } }
This can also be compiled and passed.
Array type
Above we defined the method type in the interface, so how should the array type be defined? Very simple.
interface StringArray { [index: number]: string; } var myArray: StringArray; myArray = ["Bob", "Fred"];
Then myArray is an array, and the indexer is of type number and the elements are strings.
In the definition of the interface, the name of the indexer is generally index (of course it can be changed to something else, but generally the name is kept as index). So change it to
interface StringArray { [myIndex: number]: string; } var myArray: StringArray; myArray = ["Bob", "Fred"];
Also ok.
It should be noted that the type of indexer can only be number or string.
interface Array{ [index: number]: any; } interface Dictionary{ [index: string]: any; }
The above two paragraphs can be compiled and passed.
The last thing to note is that if the interface is already an array type, the types of other attributes defined in the interface must be the element type of the array. For example:
interface Dictionary { [index: string]: string; length: number; // error, the type of 'length' is not a subtype of the indexer }
Then it will not be compiled, and length needs to be changed to string type.
Use classes to implement interfaces
Under normal circumstances, we are still accustomed to using a class to implement the required interface, rather than using the interface directly as above.
interface ClockInterface { currentTime: Date; } class Clock implements ClockInterface { currentTime: Date; constructor(h: number, m: number) { } }
In TypeScript, the class keyword is used to declare, which is the same as EcmaScript 6.
In addition, we can use interfaces to constrain the methods defined in the class.
interface ClockInterface { currentTime: Date; setTime(d: Date); } class Clock implements ClockInterface { currentTime: Date; setTime(d: Date) { this.currentTime = d; } constructor(h: number, m: number) { } }
In TypeScript, we can define constructors for interfaces.
interface ClockInterface { new (hour: number, minute: number); }
If we are naive, we might write like this:
interface ClockInterface { new (hour: number, minute: number); } class Clock implements ClockInterface { currentTime: Date; constructor(h: number, m: number) { } }
This won’t work! ! ! Because the constructor is static, the class can only implement the instance part of the interface.
Then the constructor defined in this interface has no effect? Since TypeScript provides this functionality, it is definitely not useless. The declared method is rather special:
interface ClockStatic { new (hour: number, minute: number); } class Clock { currentTime: Date; constructor(h: number, m: number) { } } var cs: ClockStatic = Clock; var newClock = new cs(7, 30);
Normally we write new Clock, here we point the Clock class to the ClockStatic interface. It should be noted that the type of newClock variable is any.
Inherited interface
Like classes, interfaces can also implement inheritance, using the extends keyword.
interface Shape { color: string; } interface Square extends Shape { sideLength: number; } var square = <Square>{}; square.color = "blue"; square.sideLength = 10;
Of course, multiple interfaces can also be inherited.
interface Shape { color: string; } interface PenStroke { penWidth: number; } interface Square extends Shape, PenStroke { sideLength: number; } var square = <Square>{}; square.color = "blue"; square.sideLength = 10; square.penWidth = 5.0;
It should be noted that although it is supported to inherit multiple interfaces, if the types of properties with the same name defined in the inherited interfaces are different, the compilation will not pass.
interface Shape { color: string; test: number; } interface PenStroke { penWidth: number; test: string; } interface Square extends Shape, PenStroke { sideLength: number; }
那么这段代码就无法编译通过了,因为 test 属性的类型无法确定。
同时使用上面所述的类型
如果仅能单一使用某种类型,那么这接口也未免太弱了。但幸运的是,我们的接口很强大。
interface Counter { (start: number): string; interval: number; reset(): void; } var c: Counter; c(10); c.reset(); c.interval = 5.0;
这样就使用到三种类型了,分别是方法(接口自己是个方法)、属性、方法(定义了方法成员)。
以上所述就是本文的全部内容了,希望大家能够喜欢。