CDK v1转v2后Lodash _.get类型推断异常排查求助
问题根源分析
这个问题的核心是TypeScript版本升级后类型检查更严格,结合你定义的JsonObject递归联合类型,导致Lodash的_.get无法正确推导返回值类型:
- 旧版TypeScript对泛型的处理更宽松,
_.get会默认返回any;新版TS会根据输入的JsonObject类型(包含字符串、数字、布尔、数组、递归对象的联合类型),推导_.get(invocationRule, "Rule")的可能类型为JsonObject | undefined,但因为联合类型的特性,TS无法确定它具体是哪种类型,最终只能推断为undefined。 - 当你用
!断言非空后,TS发现联合类型中只有对象类型能访问属性,但无法确定rule确实是对象,所以访问rule!["expression"]时,所有非对象类型(字符串/数字/布尔/数组)都没有该属性,交叉后类型退化为never,自然会提示startsWith不存在。
解决方案
方案1:为invocationRule定义更精确的接口
放弃宽泛的JsonObject,直接定义符合业务结构的类型,让TS能准确推断:
// 定义具体的规则结构 interface InvocationRule { Rule: { name: string; expression: string; }; Disabled?: boolean; } // 修改函数参数类型 private createScheduleRule(scope: Construct, invocationRule: InvocationRule, props: ScheduleProps): events.Rule { const rule = invocationRule.Rule; // 直接访问,无需_.get,类型推断完全正确 return new events.Rule(scope, `${rule.name}Rule`, { enabled: !invocationRule.Disabled, schedule: rule.expression.startsWith("P") ? events.Schedule.rate(cdk.Duration.parse(rule.expression)) : events.Schedule.expression(`cron(${rule.expression})`) // ...其他属性 }); }
方案2:手动指定_.get的泛型或使用类型断言
如果必须保留JsonObject类型,可以通过泛型或断言告诉TS返回值的具体类型:
private createScheduleRule(scope: Construct, invocationRule: JsonObject, props: ScheduleProps): events.Rule { // 方式1:指定_.get的泛型参数 const rule = _.get<JsonObject, "Rule", { name: string; expression: string }>(invocationRule, "Rule"); // 方式2:类型断言(更简洁) // const rule = _.get(invocationRule, "Rule") as { name: string; expression: string }; // 保险起见,添加类型守卫避免运行时错误 if (!rule || typeof rule !== 'object' || !('name' in rule) || !('expression' in rule)) { throw new Error("Invalid invocation rule structure"); } return new events.Rule(scope, `${rule.name}Rule`, { enabled: !_.get(invocationRule, "Disabled", false), schedule: rule.expression.startsWith("P") ? events.Schedule.rate(cdk.Duration.parse(rule.expression)) : events.Schedule.expression(`cron(${rule.expression})`) // ...其他属性 }); }
方案3:优化JsonObject的类型定义
调整递归联合类型的结构,让TS更容易推断对象类型:
// 拆分对象类型和基础类型,避免直接递归联合 type JsonValue = string | number | boolean | JsonValue[]; export type JsonObject = JsonValue | { readonly [key: string]: JsonValue };
这样修改后,TS能更清晰地区分对象和非对象类型,结合类型守卫可以缩小rule的类型范围:
private createScheduleRule(scope: Construct, invocationRule: JsonObject, props: ScheduleProps): events.Rule { const rule = _.get(invocationRule, "Rule"); if (typeof rule !== 'object' || rule === null || !('name' in rule) || typeof rule.name !== 'string' || !('expression' in rule) || typeof rule.expression !== 'string') { throw new Error("Invalid Rule structure in invocationRule"); } return new events.Rule(scope, `${rule.name}Rule`, { enabled: !_.get(invocationRule, "Disabled", false), schedule: rule.expression.startsWith("P") ? events.Schedule.rate(cdk.Duration.parse(rule.expression)) : events.Schedule.expression(`cron(${rule.expression})`) // ...其他属性 }); }
内容的提问来源于stack exchange,提问作者CustardBun
相关产品推荐
相关产品推荐

