【发布时间】:2017-07-18 13:37:37
【问题描述】:
我要么误解了 TypeScript 中的联合类型,要么文档不正确。在advanced types 部分,它使用以下示例说明:
如果我们有一个联合类型的值,我们只能访问成员 这对联合中的所有类型都是通用的。
interface Bird { fly(); layEggs(); } interface Fish { swim(); layEggs(); } function getSmallPet(): Fish | Bird { // ... } let pet = getSmallPet(); pet.layEggs(); // okay pet.swim(); // errors
但是,在我当前的 TypeScript 项目中,我似乎完全按照它所说的去做。我创建了一个类型 (FilterAction),它是由其他两种类型组成的联合类型,FilterByReportType 和 FilterByTag:
export type FilterAction = FilterByReportType | FilterByTag | FilterByCoffeeFlavour
export interface FilterByType {
type: constants.FILTER_BY_TYPE;
report_type: string;
}
export interface FilterByTag {
type: constants.FILTER_BY_TAG;
tag: string;
}
export interface FilterByCoffeeFlavour {
type: constants.FILTER_BY_COFFEE_FLAVOUR;
coffeeFlavour: string;
}
action(被称为)被传递给一个打开类型的函数,然后(这是令人惊讶的部分)它能够访问联合中所有类型不通用的成员.
function filters(state: Filter = initialState, action: FilterAction) : Filter {
switch (action.type) {
case c.FILTER_BY_TAG:
return Object.assign({}, state, { filterType: "tag", secondaryFilter: action.tag}) //accessing the uncommon member here w/o problem
case c.FILTER_BY_REPORT_TYPE:
return Object.assign({}, state, { filterType: action.report_type, secondaryFilter: ""})
case c.FILTER_BY_COFFEE_FLAVOUR:
return Object.assign({}, state, { filterType: action.coffeeFlavour, secondaryFilter: ""})
default:
return state;
}
}
此外,如果,例如,当我打开 FILTER_BY_TAG 并尝试从其他类型之一(例如 coffeeFlavour)访问成员时,TypeScript(正确地)抱怨 coffeeFlavour 没有t 存在于 FilterByTag 上,这进一步强化了我的工会正在按我希望的方式工作。
为什么在这种情况下我能够访问并非所有联合类型都通用的成员,或者相反,我的用例如何不属于文档中描述的联合范围?
【问题讨论】:
-
它是在文档中描述的联合范围内 - 通过
switching 在区分各个类型的内容上,您创建了一个 discriminated union。在每个case中,您知道(更重要的是,TypeScript 编译器知道)它是更具体的类型。 -
我正要回答这个问题,但我不知道 “智能铸造” 的打字稿术语。 +1 @jonrsharpe
-
@jonsharpe 好的,谢谢。但是,除非有扩展的文档,否则您所说的和文档中所说的完全不同。 ` 如果我们有一个联合类型的值,我们只能访问联合中所有类型共有的成员。`
-
@Leahcim 并没有完全不同,上面的链接是 to 相同的文档。您只能访问您不知道自己拥有哪种特定成员类型的普通成员;鉴于您已经明确地分支了代码,每个分支都有更多信息。如果您将页面作为一个整体,它涵盖了许多您可以更具体的情况,例如紧跟在您引用的部分之后的类型保护。它给出了一般规则,然后讨论了各种例外情况。
标签: typescript