如何在TypeScript中基于Props实现条件式接口与条件Props?
实现互斥Props的TypeScript方案
要实现传入time时禁止传入onPress(反之亦然)的约束,核心是利用TypeScript的联合类型+never类型定义互斥的Props集合,具体实现如下:
1. 拆分Props为互斥状态类型
将组件的两种状态(倒计时/可点击)拆分为独立类型,用never标记互斥属性,禁止非法传入:
// 公共属性:两种状态共享的字段 type CountdownButtonCommon = { t: (key: string) => string; // 替换原any,明确翻译函数类型 title: string; // 替换原any,明确标题类型 }; // 倒计时状态:仅含time,禁止onPress type CountdownState = CountdownButtonCommon & { time: number; // 倒计时秒数,替换原any onPress?: never; // 用never禁止传入该属性 }; // 可点击状态:仅含onPress,禁止time type ClickableState = CountdownButtonCommon & { time?: never; // 用never禁止传入该属性 onPress: () => void; // 点击回调,明确类型 }; // 最终Props类型:二选一的联合类型 type CountdownButtonProps = CountdownState | ClickableState;
2. 修改组件并处理类型收窄
将组件泛型参数改为上述联合类型,通过类型收窄让TypeScript正确推断当前状态的Props:
class CountDownButton extends Component<CountdownButtonProps> { render() { const { t, title } = this.props; // 通过'in'操作符收窄类型,判断当前为倒计时状态 if ('time' in this.props) { const { time } = this.props; return ( <View style={{ ...Layout.flexView }}> <Label text={t('common.countdown.otpCountdown')} style={{ ...LabelStyle.SubBodyText, color: Colors.black }} /> <Label text={moment.utc(time * 1000).format('HH:mm:ss')} style={{ ...LabelStyle.SubBodyTextMedium, fontWeight: '500', color: Colors.black }} /> </View> ); } else { // TypeScript自动推断为可点击状态,onPress必然存在 const { onPress } = this.props; return ( <TouchableOpacity activeOpacity={1} style={styles.buttonContainer} onPress={onPress}> <Label text={title} style={{ ...LabelStyle.BodyTextMedium, color: Colors.white }} /> </TouchableOpacity> ); } } }
效果说明
- 传入
time时若同时传onPress,TypeScript会直接报错(onPress被标记为never类型,无法赋值) - 未传入
time时,必须传入onPress,否则TypeScript提示缺少必填属性 - 替换原代码中的
any类型,让类型检查更严格,避免潜在运行时错误
内容的提问来源于stack exchange,提问作者CODEforDREAM
相关产品推荐
相关产品推荐

