TS接口
接口 定义一个类型,以 约束变量 或 约束类,
类型检查器会以接口类型为标准对值的结构进行类型检查.
使用场景: 抽象的,描述形状的,extends,implements
“鸭式辨型法”:如果它走起 路来像鸭子,叫起来也是鸭子,那么它就是鸭子
一个类可以 继承另一个类 并实现多个接口
一个类可以 实现多个接口 ,一个接口也可以 被多个类实现
一个类可以只能 继承一个父类 , 可以 被多个子类继承
变量后面:xxx
可能是,type
定义的类型,可能是class
定义的类,
可能是 interface
定义的接口,可能是 字面量,可能是 js原始类型
可选属性
interface SquareConfig {
color?: string;
width?: number;
}
任意属性
//无法预先知道有哪些新的属性的时候,可以使用 `[propName:string]:any`,propName名字是任意的
interface SquareConfig {
color: string;
width: number;
// 对象的key 可以有三种类型 string number symbol
[propName: string]: any;
}
只读属性
// 只读属性,只在创建的时候可以赋值
interface Point {
readonly x: number;
readonly y: number;
}
let p1: Point = { x: 10, y: 20 };
p1.x = 5; // error!
// 变量用const,属性用readonly
断言后可继续加属性
interface SquareConfig {
color: string;
width: number;
}
const a: SquareConfig = {
color: 'red',
width: 1,
name: 'square' // 有了as可以多属性而不报错,无as报错
} as SquareConfig
同名接口会被合并
interface SquareConfig {
color: string;
width: number;
}
interface SquareConfig {
name: string
}
const a:SquareConfig = {
color: 'red',
width: 1,
name: 'square'
}
// 继承 也是类似的效果,
// 三个属性都写 SquareConfig 里也是类似的效果
接口继承,约束类
类 实现 接口
interface Speakable{ // 代表具有speak函数的对象
speak():void;
}
interface Eatable{ // 代表具有eat函数的对象
eat():void
}
//一个类可以实现多个接口,继承后必须满足接口的条件(实现接口)
class Person implements Speakable,Eatable{
speak(){
console.log('Person说话');
}
eat(){}
}
接口 继承 另一个接口
interface Speakable {
speak(): void
}
interface SpeakChinese extends Speakable {
speakChinese(): void
}
class Person implements SpeakChinese {
speak() {
console.log('Person')
}
speakChinese() {
console.log('speakChinese')
}
}
接口 继承 多个接口
interface Shape {
color: string;
}
interface PenStroke {
penWidth: number;
}
interface Square extends Shape, PenStroke {
sideLength: number;
}
let square = <Square>{}; // Square类型的对象
square.color = "blue";
square.sideLength = 10;
square.penWidth = 5.0;
约束变量 为 对象类型
// 约束变量 接收的值 必须为对象
interface Speakable{
speak():void;
name:string;
}
let speakMan:Speakable = {
speak(){},//少属性会报错
name,
age//多属性也会报错
}
约束变量 为 函数类型
约束 变量 的值为 特定类型函数
对于约束 函数变量 的值时,值(函数) 的参数名不需要和接口中一致,
只要求 对应位置上的参数类型是兼容的
interface SearchFunc {
(source: string, subString: string): boolean;
}
let mySearch: SearchFunc;
// 下面的src sub 不指定类型也会根据function内进行类型推断
mySearch = function(src: string, sub: string): boolean {
let result = src.search(sub);
return result > -1;
}
对象字面量会经历额外属性检查
对象字面量 直接作为函数参数时 会经历 额外属性检查
将对象赋值给变量 再作为参数 传入函数调用,则不会 检查变量对象上的额外属性
interface SquareConfig {
height: number;
width: number;
}
function createSquare(config: SquareConfig):void {}
// 报错error: 'color' not expected in type 'SquareConfig'
// 因为直接传入了 对象字面量,所以经历了额外属性检查,
// 不允许拥有接口定义外的额外属性
let mySquare = createSquare({height:100, width: 100,color: "red"});
// 解决方案1,不适用 对象字面量,改写成对象 再作为参数传入
let squareOptions = { color: "red", width: 100 };
let mySquare = createSquare(squareOptions);
// 解决方案2,在 interface SquareConfig 中增加 [propName: string]: any;
约束 类 的 属性
类 实现(implements) 接口,即完成 接口 对类的约束
创建一个类可代表两个类型,静态部分的类型,实例部分的类型
interface Speakable {
name: string; //约束具有某属性
speak(words: string): void //约束具有某方法
// speak: (words: string) => void // 也可以这样写
}
class Dog implements Speakable {
name!: string;
speak(words:string) {
console.log(words);
}
}
let dog = new Dog();
dog.speak('汪汪汪');
但上面的接口Speakable 只约束的是 类的定义(静态类型)
约束 类 的 构造函数
不加new是约束变量为函数的,加new是 约束 类 的 构造函数的
// interface SearchFunc {
// (source: string, subString: string): boolean;
// }
interface WithNameClass {
new(name: string): Animalzhen
}
class Animal {
constructor(public name: string) {
}
}
// 约束clazz这个对象的构造函数必须带name
function createAnimal(clazz: WithNameClass, name: string) {
return new clazz(name);
}
let a = createAnimal(Animal, 'zhufeng');
console.log(a.name);
如果这样写会报错,因为此时的Person 描述的是实例,clazz被认为应该是某种对象
下面改成createInstance(clazz: typeof Person)
就可以
class Person{}
function createInstance(clazz: Person) { // clazz被认为应该是对象
return new clazz()
// error: 此表达式不可构造。类型 "Person" 没有构造签名。
}
let instance = createInstance(Person)
约束 变量 为 混合类型
写法为匿名函数的样子,如果写了函数名就变成描述类了
// 约束一个函数,同时这个函数还作为对象加了两个属性
interface Counter {
(start: number): string;
interval: number;
reset(): void;
}
function getCounter(): Counter {
let counter = <Counter>function (start: number) { };
counter.interval = 123;
counter.reset = function () { };
return counter;
}
let c = getCounter();
约束 变量 的 索引
对数组和对象进行约束
// 表示index必须为number,值必须为string
interface UserInterface {
[index:number]:string
}
let arr:UserInterface = ['lzy1','lzy2'];
interface NumberDictionary {
[index: string]: number;
length: number;
name: string // 错误,必须全为number
}
通过索引访问符来访问接口中的属性类型(*)
interface Person {
name: string;
age: string;
address: {
num: 316;
};
// [key: string]: any; 如果写了任意类型,则去出的val 就是任意类型
}
type PersonName = Person["name"];
type PersonNum = Person["address"]["num"]; // 316
type PropTypeUnion = keyof Person; // 取key name | age | address
type PropTypeValueUnion = Person[keyof Person]; // 取值 string | {num:316}