面试题-函数入参为interface类型进行约束

在 TypeScript 里,对函数入参为interface类型进行约束的方式有很多种。下面结合不同场景,为你详细介绍具体的实现方法:

1. 基础接口约束

你可以直接把接口当作函数参数的类型,这样就能强制要求传入的参数必须和接口结构相符。

复制代码
// 定义接口
interface User {
  name: string;
  age: number;
  email?: string; // 可选属性
}

// 函数参数被约束为User接口类型
function printUserInfo(user: User) {
  console.log(`姓名: ${user.name}, 年龄: ${user.age}`);
  if (user.email) console.log(`邮箱: ${user.email}`);
}

// 使用示例
const validUser = { name: "张三", age: 30 };
printUserInfo(validUser); // 正确

const invalidUser = { name: "李四" }; // 缺少age属性
// printUserInfo(invalidUser); // 错误:类型不匹配

2. 可选属性与只读属性约束

你可以在接口里定义可选属性(使用?)或者只读属性(使用readonly)。

复制代码
interface Config {
  readonly apiKey: string; // 只读属性,不可修改
  timeout?: number;        // 可选属性
  log?: (message: string) => void; // 可选的函数属性
}

function initConfig(config: Config) {
  // config.apiKey = "newKey"; // 错误:无法修改只读属性
  console.log(`API Key: ${config.apiKey}`);
  config.log?.("初始化完成");
}

3. 索引签名约束

当你需要处理动态属性时,可以使用索引签名。

复制代码
interface StringMap {
  [key: string]: string; // 所有属性名必须为string,属性值也必须为string
}

function printMap(map: StringMap) {
  for (const key in map) {
    console.log(`${key}: ${map[key]}`);
  }
}

const validMap = { name: "张三", city: "北京" };
printMap(validMap); // 正确

const invalidMap = { name: "李四", age: 30 }; // age属性值为number,不符合约束
// printMap(invalidMap); // 错误

4. 泛型约束

借助泛型,你能够让约束更加灵活。

复制代码
// 约束T必须包含id属性
function printId<T extends { id: number }>(obj: T) {
  console.log(`ID: ${obj.id}`);
}

const user = { id: 1, name: "张三" };
printId(user); // 正确

const invalidObj = { name: "李四" }; // 缺少id属性
// printId(invalidObj); // 错误

5. 交叉类型约束

你可以使用交叉类型(&)来组合多个接口的约束条件。

复制代码
interface Loggable {
  log: () => void;
}

interface Serializable {
  toJSON: () => object;
}

// 函数参数必须同时满足Loggable和Serializable接口
function processEntity(entity: Loggable & Serializable) {
  entity.log();
  console.log(entity.toJSON());
}

6. 接口继承约束

通过接口继承,你可以扩展已有的接口约束。

复制代码
interface Animal {
  name: string;
}

interface Mammal extends Animal {
  giveBirth: () => void;
}

// 参数必须满足Mammal接口(同时包含name和giveBirth)
function describeMammal(mammal: Mammal) {
  console.log(`${mammal.name} 是哺乳动物`);
  mammal.giveBirth();
}

7. 函数类型约束

如果你要约束函数参数本身,可以定义函数接口。

复制代码
interface Validator {
  (value: string): boolean; // 函数类型定义
}

function validateInput(input: string, validator: Validator) {
  if (validator(input)) {
    console.log("输入有效");
  } else {
    console.log("输入无效");
  }
}

// 使用示例
const isEmail: Validator = (value) => value.includes("@");
validateInput("test@example.com", isEmail); // 正确

总结

  • 直接使用接口类型来约束函数参数的结构。
  • 运用可选属性(?)和只读属性(readonly)来进行更细致的约束。
  • 利用泛型约束(T extends ...)让约束条件更加灵活。
  • 通过交叉类型(&)和接口继承(extends)组合多个约束条件。
  • 定义函数接口对函数参数进行约束。

TypeScript 的类型系统功能强大,它能在编译阶段就发现类型不匹配的错误,大大提高了代码的可靠性。你可以根据实际的需求,选择合适的约束方式。

相关推荐
那些年丶ny11 分钟前
颜色扩展库
前端·javascript·数据可视化
ihuyigui12 分钟前
海外签收通知短信接口
android·java·开发语言·前端·数据库·后端
YWL20 分钟前
OpenLayers + Vue 2 使用指南(01)
前端·javascript·vue.js
暖和_白开水41 分钟前
数据分析agent (七):contextvars 模块上下文request_id
java·前端·数据分析
程序员黑豆1 小时前
鸿蒙应用开发:Flex 组件从入门到实战
前端·华为·harmonyos
大爱编程♡1 小时前
Vue3+TypeScript+element-plus的文章管理项目(配后端接口)-退出及文章管理页面
前端·javascript·typescript
先吃饱再说1 小时前
React 组件设计:从 Props 传递到组件封装
前端·react.js
独立开阀者_FwtCoder1 小时前
最近做了一个健身小程序:智形健身助手,健身的佬们来提点意见
前端·javascript·github
舒灿1 小时前
喵ing Tab 1.0.0 正式发布
前端·ai编程
葡萄城技术团队1 小时前
当表格数据来自外部系统:SpreadJS 如何让异步公式一键刷新
前端