You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 02:37:03