TypeScript实现:对象声明后类型收缩,未定义属性调用时报错
问题描述
我需要实现这样的TypeScript行为:
- 基于外部包提供的类型定义对象
- 调用对象中已实现的属性方法时无报错
- 调用对象中未实现的可选属性方法时直接报错
简化版示例代码:
// 外部包提供的类型 type LocaleErrorMessages = { required?: () => string email?: () => string passwords?: () => string } const DanishErrorMessages: LocaleErrorMessages = { email: () => '请检查你的邮箱格式是否正确', passwords: () => "密码不符合要求" }
期望效果:
DanishErrorMessages.email()正常执行,无报错DanishErrorMessages.required()直接报错(该方法未实现)
实际场景中的外部包接口(类似Yup的StringLocale):
// 外部包接口 interface MessageParams { /* 外部包定义的参数类型 */ } interface ILocaleErrorMessages { required?: () => string; email?: () => string; passwords?: () => string; min: ({ min: number } & MessageParams ) => string; }
解决方案
核心思路是让TypeScript识别对象实际存在的属性,而非直接用外部包类型约束(后者会保留所有可选属性,调用未实现属性仅提示可能为undefined,不会直接报错)。以下是两种实现方式:
方法1:使用satisfies关键字(TypeScript 4.9+)
satisfies关键字可以确保对象符合目标类型约束,同时保留对象自身的具体类型信息:
// 外部包类型 type LocaleErrorMessages = { required?: () => string email?: () => string passwords?: () => string } const DanishErrorMessages = { email: () => '请检查你的邮箱格式是否正确', passwords: () => "密码不符合要求" } satisfies LocaleErrorMessages; // ✅ 正常执行 DanishErrorMessages.email(); // ❌ 报错:属性'required'不存在于类型'{ email: () => string; passwords: () => string; }'上 DanishErrorMessages.required();
实际场景接口的适配:
interface MessageParams { /* 外部包定义的参数类型 */ } interface ILocaleErrorMessages { required?: () => string; email?: () => string; passwords?: () => string; min: ({ min: number } & MessageParams ) => string; } const DanishErrorMessages = { email: () => '请检查你的邮箱格式是否正确', min: ({ min }) => `长度不能小于${min}位` } satisfies ILocaleErrorMessages; // ✅ 正常执行 DanishErrorMessages.min({ min: 6 }); // ❌ 报错:属性'required'不存在于当前类型 DanishErrorMessages.required();
方法2:工具类型兼容旧版TypeScript
如果你的TypeScript版本低于4.9,可以通过自定义工具类型,确保对象符合外部包类型约束的同时,保留实际属性的类型:
type LocaleErrorMessages = { required?: () => string email?: () => string passwords?: () => string } // 工具类型:校验T是否符合U的约束,不符合则抛出类型错误 type AssertSatisfies<T, U> = T extends U ? T : never; const DanishErrorMessages = { email: () => '请检查你的邮箱格式是否正确', passwords: () => "密码不符合要求" } as const satisfies LocaleErrorMessages; // 效果与方法1一致 DanishErrorMessages.email(); // ✅ DanishErrorMessages.required(); // ❌
内容的提问来源于stack exchange,提问作者Norfeldt
相关产品推荐
相关产品推荐

