我有一个界面
interface IData {
importantData: string
}
Run Code Online (Sandbox Code Playgroud)
我想isLoading在那里添加标志。如果isLoading = false,则importantData已加载并且肯定必须存在。然而,如果isLoading = true,则importantData可能存在,也可能不存在。
interface ILoadedData extends IData {
isLoading: false
}
interface ILoadingData extends Partial<IData> {
isLoading: true
}
Run Code Online (Sandbox Code Playgroud)
所以,我的最终类型是这些的联合:
type IDataWithLoading = ILoadedData | ILoadingData
Run Code Online (Sandbox Code Playgroud)
如果我尝试它对于布尔文字效果很好
const a:IDataWithLoading = ({ isLoading: false, importantData: 'secret' })
const b:IDataWithLoading = ({ isLoading: false }) // the only error, nice
const c:IDataWithLoading = ({ isLoading: true })
const d:IDataWithLoading = ({ isLoading: true, importantData: 'secret' })
Run Code Online (Sandbox Code Playgroud)
但是,在编译时我不知道东西是否正在加载,所以:
const random = Math.random() > 0.5
const e:IDataWithLoading = ({ isLoading: random, importantData: 'secret' }) // doesn't work
Run Code Online (Sandbox Code Playgroud)
它抱怨类型不兼容。这是有道理的,因为我声明了true和 的情况false,而不是 的情况boolean。然而,我涵盖了 的所有可能情况boolean,所以我感觉 TypeScript 可以理解这一点,并且我感觉我做错了什么。
然而,如果我boolean明确声明,
interface ILoadingData extends Partial<IData> {
isLoading: boolean
}
Run Code Online (Sandbox Code Playgroud)
它会isLoading = false与匹配Partial<IData>,这不是我想要的。我应该怎么办?
更新:2019-05-30 随着 TypeScript 3.5 的发布,这个问题应该通过更智能的联合类型检查来解决。以下内容适用于 3.4 及以下版本:
这是TypeScript 的一个已知限制。编译器不会尝试将联合传播到属性中。通常这样的传播不会发生(例如,{a: string, b: string} | {a: number, b: number}不能简化为{a: string | number, b: string | number}或更有用的东西)。即使在像您这样的情况下可以做某事,编译器这样做也不符合成本效益。通常这样的情况可以归结为手动引导编译器完成可能的状态。
例如,您可以尝试以下操作:
interface ILoadedDataButNotSureYet extends IData {
isLoading: boolean;
}
interface ILoadedData extends ILoadedDataButNotSureYet {
isLoading: false
}
Run Code Online (Sandbox Code Playgroud)
因此 anILoadedDataButNotSureYet确实已加载数据,但isLoading可能是trueor false。那么,你可以表示IDataWithLoading为:
type IDataWithLoading = ILoadedDataButNotSureYet | ILoadingData;
Run Code Online (Sandbox Code Playgroud)
这相当于你原来的定义,但祝你好运,让编译器注意到这一点。无论如何,您提到的所有具体实例仍然有效:
const a: IDataWithLoading = ({ isLoading: false, importantData: 'secret' })
const b: IDataWithLoading = ({ isLoading: false }) // the only error, nice
const c: IDataWithLoading = ({ isLoading: true })
const d: IDataWithLoading = ({ isLoading: true, importantData: 'secret' })
Run Code Online (Sandbox Code Playgroud)
但最后一个也有效:
const random = Math.random() > 0.5
const e: IDataWithLoading = ({ isLoading: random, importantData: 'secret' }) // works
Run Code Online (Sandbox Code Playgroud)
您可能想也可能不想真正改变IDataWithLoading。另一种方法是保留原始定义,然后对编译器施加足够的压力,直到它了解您的代码是安全的。但它并不漂亮:
const eLit = { isLoading: random, importantData: 'secret' };
const e: IDataWithLoading = eLit.isLoading ?
{...eLit, isLoading: eLit.isLoading} : {...eLit, isLoading: eLit.isLoading};
// works, but is ugly
Run Code Online (Sandbox Code Playgroud)
恶心。在这里,我们使用对象扩展来复制属性,并使用单独的isLoading属性来利用检查时发生的类型保护eLit.isLoading。三元运算符是多余的(“then”和“else”子句是相同的),但编译器得到的消息是在每种情况下值都匹配IDataWithLoading。正如我所说,恶心。
最后,您可以认为自己比编译器更聪明,并使用类型断言使其安静。这样做的优点是不会让您跳过麻烦,缺点是编译器无法帮助您维护类型安全:
const e = {
isLoading: random,
importantData: 'secret'
} as IDataWithLoading; // Take that, compiler!
Run Code Online (Sandbox Code Playgroud)
如何继续取决于您。希望有帮助;祝你好运!
| 归档时间: |
|
| 查看次数: |
4545 次 |
| 最近记录: |