不使用as关键字实现TypeScript条件类型,正确推导movies数组元素类型
报错原因
TS默认无法感知triggeredSearch布尔值和movies数组元素类型之间的绑定关系,只会将movie的类型推导为BaseMovie | MultiSearchResult联合类型,直接访问仅存在于MultiSearchResult上的media_type属性就会触发类型报错。
解决方案(无需as类型断言)
方案1:从类型层面绑定triggeredSearch和movies的关联
这是最符合TS类型系统的方案,把两个变量的状态封装为可辨识联合类型,TS会自动根据triggeredSearch的值推导movies的实际类型:
// 定义状态联合类型,把两个变量的对应关系直接声明在类型中 type MoviesState = | { triggeredSearch: false; movies: BaseMovie[]; } | { triggeredSearch: true; movies: MultiSearchResult[]; }; // 你的状态/变量按上述类型定义 const state: MoviesState = // 你的业务逻辑赋值 // 渲染时直接判断triggeredSearch即可完成自动类型收窄 <ul> {state.triggeredSearch ? state.movies.map((movie, i) => <li key={i}>{movie.media_type}</li>) : state.movies.map((movie, i) => <li key={i}>{movie.title}</li>)} </ul>
这种方案不需要额外添加运行时代码,只要在定义变量时明确两种状态的对应关系即可,类型完全安全。
方案2:使用in操作符做运行时类型守卫
如果不想改动现有变量的定义,可以在访问media_type前先判断属性是否存在,TS会自动收窄对应分支的类型:
<ul> {movies.map((movie, i) => ( <li key={i}> {!triggeredSearch ? movie.title : 'media_type' in movie ? movie.media_type : ''} </li> ))} </ul>
这种方案同时具备运行时安全性,即使后续业务逻辑变更导致类型关联失效,也不会出现访问不存在属性的问题。
方案3:自定义类型谓词守卫
如果多处代码都需要判断movie的类型,可以封装为专用的类型判断函数,提升代码可读性:
// 自定义类型守卫函数 const isMultiSearchResult = (item: BaseMovie | MultiSearchResult): item is MultiSearchResult => { return 'media_type' in item; }; // 渲染时调用即可 <ul> {movies.map((movie, i) => ( <li key={i}> {!triggeredSearch ? movie.title : isMultiSearchResult(movie) ? movie.media_type : ''} </li> ))} </ul>
内容的提问来源于stack exchange,提问作者cfoster5
相关产品推荐
相关产品推荐

