TS:インターフェースの謎
1.インターフェースの基本構文
interface Person{
name : string
}
function sayhelloto(person : Person){
console.log('hello,' + person.name);
}
let x = {
name : 'yivi',
age : 20
}
sayhelloto(x); // hello,yivi
タイプチェッカーは、対応する属性が存在し、タイプが対応している限り、属性の順序をチェックしません。それらは認識できます。
2.オプションの属性
- インターフェイスの一部の属性が不要な場合があります。場合によっては存在する必要があります。オプションの属性を持つインターフェイスは、オプションの属性の後に1つ追加するだけで済みます
?
。
interface Person {
name : string;
age : number;
phone? : number
}
3.読み取り専用属性
- 一部のオブジェクトプロパティは、オブジェクトが作成されたばかりの場合にのみ変更でき、
readonly
読み取り専用プロパティは、プロパティ名の前に追加することで指定できます。
interface Point {
readonly x : number;
readonly y : number;
}
let p : Point = {
x : 5, y : 5};
p.x = 190; // error,只能读不能赋值
- ts
ReadonlyArray<T>
にはタイプがありますが、Array<T>
配列を変更できるメソッドが削除されている点が異なります。これにより、配列の作成後に配列が変更されないようにすることができます。
let a: number[] = [1,2,3,4];
let b: ReadonlyArray<number> = a;
b[0] = 2; // error
b.push(4); // error
h.length = 20; //error
a = b; //error
//正确做法
a = b as number[];
- 変数として使用する場合は、constを使用します
- 属性として使用する場合は、読み取り専用を使用してください
4.追加の属性チェック
-
前の例では、インターフェイスにない属性を渡したため、この追加の属性は無視されますが、オプションの属性を持つインターフェイスでは失敗し、追加の属性が予期されていないことを示します。このチェックをバイパスするには、タイプアサーションを使用します。
interface SquareConfig { color?: string; width?: number; } function createSquare(config: SquareConfig): { color: string; area: number } { // ... } let mySquare = createSquare({ colour: "red", width: 100 } as SquareConfig);
-
ただし、最良の方法は、文字列インデックス署名をインターフェイスに追加することです。
interface SquareConfig { color?: string; width?: number; [propName: string] : any; }
5.関数タイプ
-
インターフェイスは、属性を持つ通常のオブジェクトを記述するだけでなく、関数タイプも記述することができます。関数を定義するときは、呼び出しシグネチャを定義する必要があります。これは、パラメーターリストと戻り値タイプのみを含む関数定義です。
interface searchFunc { (source : string, subString: string) : boolean; } let mysearch : searchFunc; mysearch = function (source : string,subString : string) { let result = source.search(subString); return result > -1; }
-
関数タイプの場合、関数のパラメーター名はインターフェースのパラメーター名と一致している必要はありません。関数のパラメータは1つずつチェックされ、対応する位置のパラメータタイプは互換性がある必要があります。タイプを指定しない場合、TypeScriptはパラメータータイプを推測します。関数の戻り値の型がインターフェイスの戻り値の型と異なる場合、型チェッカーは警告を出します。
mysearch = function(src : string,sub : string) : boolean { let result = src.search(sub); return result > -1; } // or mysearch = function(src , sub){ let result = src.search(sub); return result > -1; }
6.インデックス可能なタイプ
-
インデックス可能な型には、オブジェクトインデックスの型と、対応するインデックスの戻り値の型を記述するインデックスシグネチャがあります。
interface StringArray{ [index : number] : string; } let myarr : StringArray; myarr = ["yivi","huang"]; let mystr : string = myarr[0];
-
TypeScriptは、文字列と数値の2種類のインデックス署名をサポートしています。両方のタイプのインデックスを同時に使用できますが、数値インデックスの戻り値は、文字列インデックスの戻り値タイプのサブタイプである必要があります。これは、
number
インデックス作成に時間を使用すると、JavaScriptがそれを変換string
してインデックスオブジェクトに移動するためです。つまり、100
(onenumber
)を使用してインデックスを作成することは、"100"
(onestring
)を使用してインデックスを作成することと同じであるため、2つは一貫している必要があります。class Animal { name: string; } class Dog extends Animal { breed: string; } // 错误:使用数值型的字符串索引,可能会以字符串进行索引,有时会得到完全不同的Animal! interface NotOkay { [x: number]: Animal; [x: string]: Dog; }
-
文字列インデックスシグニチャは
dictionary
パターンを適切に記述でき、すべての属性が戻り値の型と一致することも保証します。 -
文字列インデックスが宣言されて
obj.property
おりobj["property"]
、2つの形式が宣言されている可能性があるためです。interface NumberDictionary{ [index: string] : number; length : number; // ok,返回值与索引返回类型一致 name : string; // error,string与索引返回类型不一致 }
-
同時に、インデックスタイプが読み取り専用に設定されているとも言えます。
7.クラス
-
Javaと同様に、TypeScriptもインターフェイスを使用して、クラスが実装する必要のあるプロパティまたはメソッドを適用できます。
interface clockInterface{ currentTime : Date; setTime(d : Date); } class Clock implements clockInterface{ currentTime : Date; setTime(d : Date){ this.currentTime = d; } constructor(h : number,m : number){ } }
-
クラスには、静的パーツタイプとインスタンスタイプの2つのタイプがあります。
-
コンストラクターシグニチャーを使用してインターフェースを定義し、それを実装するクラスを定義すると、エラーが報告されます。
-
クラスがインターフェースを実装する場合、そのインスタンス部分のみが型チェックされるためです。コンストラクターはクラスの静的部分に存在するため、検査の範囲には含まれません。
// 以下定义会报错 // Class 'Clock' incorrectly implements interface 'ClockConstructor'. Type 'Clock' provides no match for the signature 'new (hour: number, minute: number): any'. interface ClockConstructor { new (hour: number,minute : number); // 静态类型 } class Clock implements ClockConstructor{ currentTime : Date; constructor(h: number,m:number); }
// 正确示范 interface ClockConstructor { new (hour: number, minute: number): ClockInterface; } interface ClockInterface { tick(); } function createClock(ctor: ClockConstructor, hour: number, minute: number): ClockInterface { return new ctor(hour, minute); // 返回类型为ClockInterface } class DigitalClock implements ClockInterface { constructor(h: number, m: number) { } tick() { console.log("beep beep"); } } let digital = createClock(DigitalClock, 12, 17);
-
ので、
createClock
最初のパラメータがあるClockConstructor
中で、タイプcreateClock(DigitalClock, 12, 17)
も、それがチェックされますDigitalClock
、それはコンストラクタシグネチャに準拠しているかどうか。
8.継承されたインターフェース
- Javaと同様に、TypeScriptもインターフェイスの継承をサポートしています。
- 1つのインターフェースが複数のインターフェースを継承できます。
9.混合タイプ
-
typescriptの利点は、柔軟性と動的性です。オブジェクトは、関数とオブジェクトとして同時に使用でき、追加の属性があります。
interface Counter{ (start : number) : string; interval : number; reset : void; } function getCounter() : Counter{ let counter = <Counter>function (start : number){ }; counter.interval = 100; counter.reset = function(){ }; return counter; } let c = getCounter(); c(10); c.reset(); c.interval = 20;
10.インターフェース継承クラス
-
インターフェイスがクラスを継承する場合、クラスのメンバーは継承されますが、実装は継承されません。つまり、プライベート変数または保護変数を使用してインターフェイス継承クラスを作成する場合、このインターフェイスはこのクラスまたはそのサブクラスによってのみ実装できます。
class Control { private state: any; } interface SelectableControl extends Control { select(): void; } class Button extends Control implements SelectableControl { select() { } // ok,因为state为私有成员,所以只有子类才能实现SelectableControl接口 } class TextBox extends Control { select() { } } // 错误:“Image”类型缺少“state”属性。 class Image implements SelectableControl { select() { } }
-
Control
クラス内ではSelectableControl
、インスタンスを介してプライベートメンバーにアクセスできますstate
。実際、SelectableControl
インターフェースとselect
メソッドControl
を持つクラスは同じです。