[ts入门03]interface

849 阅读4分钟

interface 基本

是什么?

  1. 用户自定义的类型,定义基本类型中不存在类型
  2. 相当于c++ 的结构体 struct (个人理解)

作用

描述普通对象

  • 固定属性名和类型,用于类型检查 例子1,2,3
  • 定义变量比接口少了一些属性是不允许的
  • 多一些属性也是不允许的

描述函数类型

  • 固定输入:输出类型,相当于把函数的框架搭建好,例子4

描述索引类型

  • 固定object/array的索引类型,索引是指objec.key或者array.index,例子5

语法 接口一般首字母大写。 有的编程语言中会建议接口的名称加上 I 前缀

例子1 属性检查

// interface定义
interface Person { firstName: string; lastName: string}

//  interface使用: 函数形参
function greeter(p: Person){
    return `${p.firstName} ${p.lastName}`
}

// 隐式类型检查
let intUser1 = {firstName: 'san', lastName: 'zhang'}; // ok
console.log("intUser1: ", greeter(intUser1));  // intUser1:  san zhang

// 显式类型检查
let intUser2: Person = {firstName: 'san', lastName: 'zhang'}; // ok
console.log("intUser2: ", greeter(intUser2));  // intUser2:  san zhang

/*
多的属性 nickName
*/ 
let initUser31 = {firstName: 'san', lastName: 'zhang', nickName: 'xiaozhang'};  // ok
console.log("initUser31: ", greeter(initUser31)); // initUser31:  san zhang

// let initUser32:Person = {firstName: 'san', lastName: 'zhang', nickName: 'xiaozhang'};  // compile error!
// console.log("initUser32: ", greeter(initUser32));

console.log("initUser fun: ", greeter({firstName: 'san', lastName: 'zhang', nickName: 'xiaozhang'} as Person));  // ok initUser fun:  san zhang

检查分类

  1. 隐式类型检查
  2. 显式类型检查

检查变量

  1. 检查存在:属性是不是都有?
  2. 检查类型:类型是不是正确?
  3. 不检查顺序:属性顺序可以随意
  4. 不检查多余:变量多余属性没关系(显示类型除外)

例子2 可选属性

interface SquareConfig { color?: string, width?: number }

// config表示参数类型, color/area表示返回值类型
function createSquare(config: SquareConfig): {color: string, area: number} {
    let newSquare = {color: 'white', area: 100}; // 返回值默认结果
    if(config.color){
        newSquare.color = config.color;
    };
    if(config.width){
        newSquare.area = config.width * config.width;
    }
    console.log('newSquare: ', newSquare);
    return newSquare;
}

createSquare({});                            // { color: 'white', area: 100 }
createSquare({color: 'black'});             //  { color: 'black', area: 100 }
createSquare({width: 5});                   //  { color: 'white', area: 25 }
createSquare({color: 'red', width: 1});     // { color: 'red', area: 1 }

// 使用类型断言(类型转化)可以解决多余属性的检查
createSquare({color: 'red', opactiy: 0.5} as SquareConfig);  //  { color: 'red', area: 100 }

可选属性是什么?

属性名称后接问号

可选属性作用? 对可能属性进行预定义;

例子3 只读属性

// 只读属性
interface Point { readonly x: number; readonly y: number }
let p1: Point = {x: 1, y:2}
console.log(p1.x, p1.y); //ok  1 2
// p1.x = 3; // error: Cannot assign to 'x' because it is a read-only property.

// 只读数组
let intArr2: ReadonlyArray<number> = [4,5,6];
console.log(intArr2); // [ 4, 5, 6 ]
// intArr2[0] = 400; //  error:Index signature in type 'readonly number[]' only permits reading.

只读属性的定义?

通过readonly, ReadonlyArray

只读属性的作用?

只有第一次初始化时可以被赋值,

之后只能读,不能写了

例子4 函数接口

interface searchFun {
    (source: string, subString: string) : boolean
}
let mySearchFun: searchFun = function(src: string, sub:string): boolean{
    let result = src.search(sub);
    return result > -1;
}
console.log(mySearchFun('abc123abc', '123')); // true
console.log(mySearchFun('abc123abc', '1234')); // false

语法

(参数1,参数2) : 返回值

作用

描述函数

例子5 索引签名

/*
索引签名为number
*/ 

// 描述key为number,value为number的对象 (=>数组)
interface Grades {
    [x: number]: number
};

let myGrade: Grades = [90,95,100];
let grade0: number = myGrade[0]
console.log(`grade0=${grade0}`); // grade0=90

/* 
索引签名为string 
*/

// 描述key为string,value为number的对象 (=>普通对象)
interface NameGrades {
    [y: string]: number
};
let myNameGrades: NameGrades = {'lily': 80, 'lucy': 90,  'Jonny': 100};
let lucyGrades: number = myNameGrades['Jonny'];
console.log(`lucyGrades=${lucyGrades}`); // lucyGrades=100
/* 
索引签名为number+string 
*/

// 描述key为string或者number,value为string的对象 (=>普通对象)
interface Okay {
    [x: number]: string;
    [x: string]: string;
}
let myOkay: Okay = {'name': 'micky', 10: 'haha'};
let okRet1: string = myOkay['name']; // okRet1=micky
let okRet2: string = myOkay[10]; //  okRet2=haha

// 注意:如果2个的返回值类型不同时,编译报错
//  Numeric index type 'number' is not assignable to string index type 'string'.
// interface NotOkay {
//     [x: number]: number;
//     [x: string]: string;
// }
/* 
索引签名包含index+length 
*/

interface nameDictionary {
    [index: number]: number, 
    length: number, // ok length属于字符串索引
}
let myNameDictionary: nameDictionary = [1,2,3];
console.log(`myNameDictionary=${myNameDictionary}`); // myNameDictionary=1,2,3

/* 
索引签名可以设置为只读 
*/
interface ReadonlyStringArray {
    readonly [index: number]: string;
}

let myReadonlyStringArray: ReadonlyStringArray = ['Alice', 'Bob'];
// myReadonlyStringArray=Alice,Bob
console.log(`myReadonlyStringArray=${myReadonlyStringArray}`);

索引签名是什么?

索引下标: objec.key或者array.index

支持两种索引签名

  1. 字符串
  2. 2数

例子6 接口的混合类型

接口描述的函数,还可以附加属性和其它方法

interface Counter {
    (start: number): string; // 函数描述,接口的本质
    interval: number; // 函数包含interval属性
    reset(): void;  // 函数包含reset方法
}

function getCounter(): Counter {
    // 函数描述的实现
    let counterStart = function (start:number) {
        console.log(`start ${start}`);        
    }
    
    // 返回值
    let counter = <Counter> counterStart;
  
    // 函数属性的描述
    counter.interval = 123;

  	// 函数方法的描述  
    counter.reset = function() {
        console.log('reset!');
    }
  
    return counter;
}


let myCount1 = getCounter(); 

// { [Function: counterStart] interval: 123, reset: [Function] }
console.log(myCount1); 

// 调用函数
myCount1(10); // start 10

// 调用函数的reset方法
myCount1.reset(); // reset!

// 赋值函数的interval属性
myCount1.interval = 5.0;