基于其他成员类型的条件成员类型
问题描述:
是否可以根据特定条件指定多个可能的成员类型?例如,给予以下类型:基于其他成员类型的条件成员类型
interface DataItem {
value: boolean | Date | string | string[];
options: undefined | string[];
}
我想说明,如果:
-
value
是boolean
类型或Date
的那么options
必须是undefined
类型。 -
value
是string
型或string[]
的然后options
必须是string[]
类型。
有没有办法在当前版本的TypeScript(2.2)中指定上述约束?此外,如果是那么我假设一个部件上添加型后卫应该适用于其他成员,即:
let data: DataItem;
if (typeof data.value === 'boolean') {
data.options = ['a']; // => Error Type 'string[]' is not assignable to type 'undefined'.
}
我尝试以下,但没有奏效:
interface BooleanOrDateItem {
value: boolean | Date;
}
interface StringOrStringArrayDataItem {
value: string | string[];
options: string[];
}
type DataItem = BooleanOrDateItem | StringOrStringArrayDataItem;
let data: DataItem;
if (typeof data.value === 'string') {
// I would expect this to work but the compiler complains
// => Property 'options' does not exist on type 'DataItem'.
// Property 'options' does not exist on type 'BooleanOrDateItem'.
data.options = ['a'];
}
明确铸造StringOrStringArray
明显作品
if (typeof data.value === 'string') {
(<StringOrStringArrayDataItem>data).options = ['a'];
}
但不应编译器做的我的代表,因为它有足够的信息来推断data
是StringOrStringArrayDataItem
?
答
我相信你正在寻找User-defined Type Guards。在每个if
语句之后,如果返回值为true
,TypeScript会将dataItem
的类型缩小为正确的类型。
interface DataItem {
value: boolean | Date | string | string[];
options: undefined | string[];
}
interface BoolOrDateDataItem extends DataItem {
value: boolean | Date;
options: undefined;
}
interface StringDataItem extends DataItem {
value: string | string[];
options: string[];
}
function isBoolOrDateDataItem(dataItem: DataItem): dataItem is BoolOrDateDataItem {
return typeof dataItem.value === 'boolean' || dataItem.value instanceof Date;
}
function isStringDataItem(dataItem: DataItem): dataItem is StringDataItem {
return typeof dataItem.value === 'string' || dataItem.value instanceof Array;
}
let dataItem: DataItem = {
value: true,
options: undefined
} // Or whatever it may be
if (isStringDataItem(dataItem)) {
dataItem.value = new Date(); // TypeScript warns value must be string | string[] - knows it is a StringDataItem here
} else if (isBoolOrDateDataItem(dataItem)) {
dataItem.value = true; // No error
}
这绝对有点冗长,但似乎是推荐的做事方式。
我觉得这种方法是行不通的,我会使用'任何'数据类型或创建多个接口,并找出你需要使用工厂。 –