Dans TypeScript, les interfaces sont utilisées comme contraintes. Une fois compilées en JavaScript, toutes les interfaces seront effacées car il n'y a pas de notion d'interface en JavaScript.
Prenons un exemple simple :
function printLabel(labelledObj: { label: string }) { console.log(labelledObj.label); } var myObj = { size: 10, label: "Size 10 Object" }; printLabel(myObj);
Ensuite dans cette méthode, le type de labeledObj est {label: string}, ce qui peut paraître un peu compliqué, mais si on regarde la déclaration de myObj ci-dessous, on saura qu'il s'agit d'une déclaration avec un attribut size ( la valeur est 10) et un objet avec un attribut label (valeur "Objet taille 10"). Par conséquent, le type du paramètre de méthode labeledObj est {label: string}, ce qui signifie que le paramètre a un attribut label de type string.
Cependant, écrite ainsi, cette méthode semble encore un peu déroutante. Vous pouvez ensuite utiliser une interface pour définir le type de paramètre de cette méthode.
interface LabelledValue { label: string; } function printLabel(labelledObj: LabelledValue) { console.log(labelledObj.label); } var myObj = { size: 10, label: "Size 10 Object" }; printLabel(myObj);
Attributs facultatifs
Parfois, nous n'avons pas besoin que l'attribut existe, nous pouvons donc utiliser l'attribut facultatif pour le définir.
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" });
Ensuite, nous transmettons un objet qui implémente une interface SquareConfig dans la méthode createSquare.
Puisqu’il est totalement dispensable, pourquoi avons-nous besoin de le définir ? Définir des propriétés facultatives présente deux avantages par rapport à ne pas les définir du tout. 1. S'il y a des attributs, le type peut être contraint, ce qui est très critique ; 2. Vous pouvez obtenir des invites de syntaxe intelligentes. Si vous écrivez par erreur color dans le corps de la méthode en tant que collor, la compilation échouera.
Type de méthode
En JavaScript, la fonction méthode est un type de base. Dans la pensée orientée objet, l'implémentation des interfaces est réalisée par des classes. En tant que type, une fonction peut-elle implémenter des interfaces ? La réponse est oui.
Dans TypeScript, nous pouvons utiliser des interfaces pour contraindre les signatures de méthodes.
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; } }
Dans le code ci-dessus, nous définissons une interface, qui contraint la signature d'une méthode. Cette méthode a deux paramètres de chaîne et renvoie une valeur booléenne. Dans le deuxième morceau de code, nous déclarons l'implémentation de cette interface.
Il convient de noter que le compilateur vérifie uniquement si le type est correct (type de paramètre, type de valeur de retour), nous pouvons donc changer le nom du paramètre en autre chose.
var mySearch: SearchFunc; mySearch = function(src: string, sub: string) { var result = src.search(sub); if (result == -1) { return false; } else { return true; } }
Cela peut également être compilé et transmis.
Type de tableau
Ci-dessus, nous avons défini le type de méthode dans l’interface, alors comment définir le type de tableau ? Très simple.
interface StringArray { [index: number]: string; } var myArray: StringArray; myArray = ["Bob", "Fred"];
Alors myArray est un tableau, et l'indexeur est de type number et les éléments sont des chaînes.
Dans la définition de l'interface, le nom de l'indexeur est généralement index (bien sûr il peut être changé en autre chose, mais généralement le nom est conservé comme index). Alors changez-le en
interface StringArray { [myIndex: number]: string; } var myArray: StringArray; myArray = ["Bob", "Fred"];
Très bien aussi.
Il est à noter que le type d'indexeur ne peut être qu'un nombre ou une chaîne.
interface Array{ [index: number]: any; } interface Dictionary{ [index: string]: any; }
Les deux paragraphes ci-dessus peuvent être compilés et transmis.
La dernière chose à noter est que si l'interface est déjà de type tableau, les types des autres attributs définis dans l'interface doivent être le type d'élément du tableau. Par exemple :
interface Dictionary { [index: string]: string; length: number; // error, the type of 'length' is not a subtype of the indexer }
Ensuite, il ne sera pas compilé et la longueur doit être modifiée en type chaîne.
Utiliser des classes pour implémenter des interfaces
Dans des circonstances normales, nous sommes toujours habitués à utiliser une classe pour implémenter l'interface requise, plutôt que d'utiliser l'interface directement comme ci-dessus.
interface ClockInterface { currentTime: Date; } class Clock implements ClockInterface { currentTime: Date; constructor(h: number, m: number) { } }
Dans TypeScript, le mot-clé class est utilisé pour déclarer, ce qui est le même qu'EcmaScript 6.
De plus, nous pouvons utiliser des interfaces pour contraindre les méthodes définies dans la classe.
interface ClockInterface { currentTime: Date; setTime(d: Date); } class Clock implements ClockInterface { currentTime: Date; setTime(d: Date) { this.currentTime = d; } constructor(h: number, m: number) { } }
En TypeScript, nous pouvons définir des constructeurs pour les interfaces.
interface ClockInterface { new (hour: number, minute: number); }
Si nous sommes naïfs, nous pourrions écrire ainsi :
interface ClockInterface { new (hour: number, minute: number); } class Clock implements ClockInterface { currentTime: Date; constructor(h: number, m: number) { } }
Ça ne marchera pas ! ! ! Le constructeur étant statique, la classe ne peut implémenter que la partie instance de l'interface.
Alors le constructeur défini dans cette interface n'a aucun effet ? Puisque TypeScript fournit cette fonctionnalité, elle n’est certainement pas inutile. La méthode déclarée est assez particulière :
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);
Normalement, nous écrivons une nouvelle Clock, ici nous pointons la classe Clock vers l'interface ClockStatic. Il convient de noter que le type de variable newClock est quelconque.
Interface héritée
Comme les classes, les interfaces peuvent également implémenter l’héritage, en utilisant le mot-clé extends.
interface Shape { color: string; } interface Square extends Shape { sideLength: number; } var square = <Square>{}; square.color = "blue"; square.sideLength = 10;
Bien sûr, plusieurs interfaces peuvent également être héritées.
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;
Il convient de noter que bien qu'il soit pris en charge pour hériter de plusieurs interfaces, si les types de propriétés portant le même nom définis dans les interfaces héritées sont différents, la compilation ne réussira pas.
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;
这样就使用到三种类型了,分别是方法(接口自己是个方法)、属性、方法(定义了方法成员)。
以上所述就是本文的全部内容了,希望大家能够喜欢。