Typescript —— 接口

90 阅读4分钟

基本使用

接口的本质作用是: 定义对象的数据结构

// 不使用接口

// 声明函数 (参数使用对象解构)
function getFullname({firstName, lastName}): string { 
    return `${firstName}-${lastName}`
}

// 使用函数

// 正常使用 --- 编译通过
getFullname({
    firstName: 'Klaus',
    lastName: 'Wang'
}) // => Klaus-wang

// 非正常使用 --- 编译依旧通过
getFullname({
    firstName: 'Klaus',
    lastName: 123
}) // => Klaus-123
// 使用接口

// 定义接口 
// 1. 接口首字母一般大写
// 2. 为了声明数据类型是一个接口类型,所以可以在命名前加上I, 即IUserInfo
interface UserInfo { 
    firstName: string,
    lastName: string
}


function getFullname({firstName, lastName}: UserInfo):string { 
    return `${firstName}-${lastName}`
}

getFullname({
    firstName: 'Klaus',
    lastName: 'Wang'
}) // -> Success

getFullname({
    firstName: 'Klaus',
    lastName: 123
}) // -> Error

另一种写法

function getFullname({firstName, lastName}: { 
    firstName: string,
    lastName: string
}):string { 
    return `${firstName}-${lastName}`
}

可选参数

// 可选参数
interface UserInfo {
    name: string,
    gender?: string  // 设置gender是可选参数,可以传递也可以不传递
}

function getUserInfo({ name, gender }: UserInfo) { 
    return `name = ${name}, gender = ${gender || 'male'}`
}

// 在这里不传递gender
alert(getUserInfo({
    name: 'Klaus'
}))

多余属性检测

// 如何绕过多余属性检测的方式

// 什么是多余属性检测
interface UserInfo {
    name: string,
    gender?: string
}

function getUserInfo({ name, gender }: UserInfo) { 
    return `name = ${name}, gender = ${gender || 'male'}`
}

// 在调用的时候,多传入了一个没有使用到的属性 age
// ts检测出传入的对象,多了一个属性,所以会报错
// 这就是多余属性检测
alert(getUserInfo({
    name: 'Klaus',
    gender: 'male',
    age: 23
}))

方式1

// 类型断言
interface UserInfo {
    name: string,
    gender?: string
}

function getUserInfo({ name, gender }: UserInfo) { 
    return `name = ${name}, gender = ${gender || 'male'}`
}

alert(getUserInfo({
    name: 'Klaus',
    gender: 'male',
    age: 23
} as UserInfo))

方式2

// 索引签名
interface UserInfo {
    name: string,
    gender?: string,
    // 这里是索引签名
    // props 是你的参数名称,任意
    // string: 表示的是你参数名称必须是一个字符串字符串
    // any: 表示你传入的参数的类型任意
    // []: 表示个数不唯一,可以是多个
    [props: string]: any 
}

function getUserInfo({ name, gender }: UserInfo) { 
    return `name = ${name}, gender = ${gender || 'male'}`
}

alert(getUserInfo({
    name: 'Klaus',
    gender: 'male',
    age: 23
}))

方式3

// 类型兼容性
interface UserInfo {
    name: string,
    gender?: string
}

function getUserInfo({ name, gender }: UserInfo) { 
    return `name = ${name}, gender = ${gender || 'male'}`
}

/**
 * 类型兼容性原理
 *  有a和b 2个对象
 *  
 *  如果 a = b 成立
 *  则表示
 *  b中有的属性,a中都有,且必须都存在
 *  但是a中可以有b中没有的属性
 *  
 * 
 *  例如
 *  a = {name: 'Klaus'}
 *  b = {name: 'Steven'}
 *  
 *  a = b // -> Success
 * 
 *  例如
 *  a = {name: 'Klaus', age: 23}
 *  b = {name: 'Steven'}
 *  
 *  a = b // -> Success
 *
 *  例如
 *  a = {name: 'Klaus'}
 *  b = {name: 'Steven', age: 23}
 *  
 *  a = b // -> Error
 */
const args = {
    name: 'Klaus',
    gender: 'male',
    age: 23
}

alert(getUserInfo(args))

只读属性

// 只读属性
interface UserInfoInter { 
    readonly name: string
}

let user: UserInfoInter = {
    name: 'Klaus'
}

user.name = 'Steven' // -> Error

定义特殊对象的类型

数组

// 数组 是一种特殊的对象
// 所以可以设置数组的属性是只读的
interface ArrInter { 
    0: number,
    readonly 1: number
}

let arr: ArrInter = [213, 321]

arr[0] = 222 // -> Success
arr[1] = 222 // -> Error

函数

interface addFunc { 
    (num1: number, num2: number): number
}

const add: addFunc = (num1, num2) => num1 + num2

索引

// 为索引定义类型

// 定义一个对象
// 对象的属性名为字符串
// 对象的属性值也是字符串
interface RoleDic { 
    [prop: string]: string
}

/**
 * 在对象中,所有的属性名全部会自动被转换为字符串字符串
 * 也就是说 1 === '1'
 *         true ==== 'true'
 */
const role: RoleDic = {
    name: 'Klaus',
    1: 'demo',
    true: 'true'
}

接口

接口的作用 是为了提取对象中的公共属性,以便于提升复用性

// 不使用接口
interface PersonnInter { 
    name: string
}

interface UserInter { 
    name: string,
    age: number
}

interface StudentInter { 
    name: string,
    gender: string
}


// 很明显,这里的name属性,重复出现了3次

// 使用接口 进行定义
// 不使用接口
interface PersonnInter { 
    name: string
}

interface UserInter extends PersonnInter { 
    age: number
}

interface StudentInter extends PersonnInter { 
    gender: string
}

混合类型

即一个定义可以作为2种或者以上类型来进行使用

举个例子: 一个对象可以同时做为函数和对象使用,并带有额外的属性。

// 定义一个计数器,每调用一次 变量加一,并输出变量的值
let count = 0

function add() { 
    return count ++
}

但是这么做,会导致存在全局变量count,所以会存在污染全局变量

// 方式1 --- IIFE
const add = (() => { 
    let count = 0

    return () => ++count
})()

// 方式2 --- 混合类型
const add = () => { 
    return ++add.count
}

// 函数是一种特殊的对象
add.count = 0
// ---> 此时add 即是函数,又是对象,所以add就是一种混合类型
// 使用ts进行实现混合类型
interface Counter {
    (): void,
    count: number
}

// 工厂函数
const getCounter = (): Counter => { 
    const c = () => ++c.count
    c.count = 0
    return c
}

const counter: Counter = getCounter()