TypeScript参数类型识别:如何优化属性存在判断逻辑?
TypeScript 优化类型判断逻辑的惯用写法
问题背景
现有代码中需要判断args是否已定义且包含actions属性,当前使用hasOwnProperty并禁用了eslint规则,希望用TypeScript惯用写法重构,让代码更清晰安全:
class Actions { actions: string[] } type Argument = object | Actions; export class GetFilesContext implements IExecutable { execute( args: Argument, response: ServerResponse<IncomingMessage> ): void { ... // eslint-disable-next-line no-prototype-builtins if( args && args.hasOwnProperty( "actions" )) { ctxt.actions.length = 0; ctxt.actions.push( ...(args as Actions).actions ); } response.end( JSON.stringify( ctxt )); } }
解决方案
1. 自定义类型守卫(最推荐,TypeScript原生支持)
编写类型谓词函数,让TypeScript自动推导类型,无需手动断言:
class Actions { actions: string[] = [] } // 建议初始化属性避免undefined type Argument = object | Actions; // 自定义类型守卫函数 function isActions(arg: Argument): arg is Actions { // 先判断非空,再判断是对象类型,最后检查是否包含actions属性 return arg !== null && typeof arg === 'object' && 'actions' in arg; } export class GetFilesContext implements IExecutable { execute(args: Argument, response: ServerResponse<IncomingMessage>): void { // ... if (isActions(args)) { ctxt.actions.length = 0; ctxt.actions.push(...args.actions); // 无需类型断言,TypeScript自动识别为Actions类型 } response.end(JSON.stringify(ctxt)); } }
这种方式既安全又清晰,后续所有用到args的地方都会自动获得类型提示,避免类型错误。
2. 直接使用in操作符(简洁写法)
如果不想单独写类型守卫函数,可以直接用in操作符做条件判断,无需禁用eslint:
export class GetFilesContext implements IExecutable { execute(args: Argument, response: ServerResponse<IncomingMessage>): void { // ... if (args && 'actions' in args) { ctxt.actions.length = 0; ctxt.actions.push(...(args as Actions).actions); } response.end(JSON.stringify(ctxt)); } }
'actions' in args会检查对象自身或原型链上是否存在该属性,对于当前的Argument类型来说足够准确,写法比hasOwnProperty更简洁。
3. 正确使用instanceof(仅限类实例场景)
如果args是通过new Actions()创建的类实例,instanceof可以直接生效(之前失败可能是因为args不是类实例,而是普通对象):
export class GetFilesContext implements IExecutable { execute(args: Argument, response: ServerResponse<IncomingMessage>): void { // ... if (args instanceof Actions) { ctxt.actions.length = 0; ctxt.actions.push(...args.actions); } response.end(JSON.stringify(ctxt)); } }
注意:这种方式只适用于args是Actions类的实例对象,如果args是API传入的普通JSON对象(plain object),则instanceof不生效,此时建议用前两种方法。
补充说明
- 单独用
typeof无法区分object和Actions实例,因为两者的typeof结果都是'object',所以需要结合其他判断条件。 - 原代码中
hasOwnProperty需要禁用eslint是因为存在安全风险(若对象重写了hasOwnProperty方法),更安全的替代写法是Object.prototype.hasOwnProperty.call(args, 'actions'),但不如in或类型守卫简洁。
内容的提问来源于stack exchange,提问作者Aubin
相关产品推荐
相关产品推荐

