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

TypeScript中如何定义包含多种可选结构的Keyframe接口

问题根因

你最初的写法触发类型错误的核心原因是TypeScript的索引签名约束规则:当接口定义了字符串索引签名时,所有显式声明的属性值类型必须和索引签名的返回值类型兼容。你写的[property: string]: string要求所有字符串键对应的值都必须是字符串类型,但easing和transform的值是对象类型,自然不满足兼容要求,直接抛错。

实现代码

通过「基础接口拆分 + 联合类型 + never类型排除非法键」的方式实现,完全满足你列出的结构规则:

// 所有关键帧的公共基础结构,强制要求存在easing属性
interface BaseKeyframe {
  easing: Record<string, string>
}

// 仅包含变换属性的关键帧形态
interface TransformOnlyKeyframe extends BaseKeyframe {
  transform: Record<string, string>
  // 索引签名兼容easing/transform的对象类型,禁止出现其他字符串类型的CSS属性
  [key: string]: Record<string, string> | never
}

// 包含非变换属性的关键帧形态(可同时携带transform属性)
interface WithCssPropertyKeyframe extends BaseKeyframe {
  transform?: Record<string, string>
  // 索引签名同时兼容对象类型的easing/transform、字符串类型的普通CSS属性
  [key: string]: Record<string, string> | string | never
}

// 最终Keyframe为两种形态的联合类型,自动满足「必须有transform或至少一个普通CSS属性」的强制约束
type Keyframe = TransformOnlyKeyframe | WithCssPropertyKeyframe
规则匹配说明

该实现完全覆盖你提出的4条结构约束:

  • 针对规则1:所有联合分支都继承BaseKeyframe,强制要求必须存在easing对象,支持空对象或任意字符串键值对。
  • 针对规则2:两个分支都声明了可选/必选的transform属性,值为Record<string,string>类型,符合变换属性存储要求。
  • 针对规则3:索引签名通过never类型排除了非法值,普通CSS属性值只能是字符串类型,且不会和easing/transform的类型冲突。
  • 针对规则4:联合类型自动拦截非法结构:如果不传transform,就必须匹配WithCssPropertyKeyframe分支,要求至少存在一个字符串类型的普通CSS属性;如果不传普通CSS属性,就必须匹配TransformOnlyKeyframe分支,要求必须存在transform对象,不会出现只有空easing的无效关键帧。
校验示例
// 合法:仅变换属性关键帧
const transformKeyframe: Keyframe = {
  easing: { translateX: 'easeInOutQuad' },
  transform: { translateX: '10px' }
} 

// 合法:仅非变换属性关键帧
const propertyKeyframe: Keyframe = {
  easing: { opacity: 'linear' },
  opacity: '0.5' 
} 

// 合法:混合属性关键帧
const mixedKeyframe: Keyframe = {
  easing: {
    translateX: 'easeInOutQuad',
    translateY: 'easeInOutQuad',
    opacity: 'linear',
    fill: 'linear'
  },
  transform: {
    translateX: '10px',
    translateY: '10px',
  },
  opacity: '0.5',
  fill: 'red'
} 

// 合法:空easing+普通属性
const finalKeyframe: Keyframe = {
  easing: {},
  opacity: '0.5' 
}

// 以下为非法示例,TS会直接抛类型错误
// 1. 既无transform也无普通CSS属性
const invalid1: Keyframe = { easing: {} }
// 2. 普通CSS属性值为非字符串类型
const invalid2: Keyframe = { easing: {}, opacity: 0.5 }

注:你提供的mixedKeyframe示例中opacity:、fill:键名多了尾冒号,属于笔误,去掉冒号即可正常通过类型校验。

内容的提问来源于stack exchange,提问作者cameralibre

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.09 16:15:44