使用流类型对函数的参数进行子类型化
Subtyping arguments of functions with flowtype
我的应用程序中几乎没有几种具有共同属性的类型。我将公共属性抽象为分离类型。现在我想编写一个函数,它接受任何具有共同基类型的类型。
这几行比以下文字更好地解释了问题:
type Box = {
width: number,
height: number,
}
// is like Box + it has position
type PositionedBox = Box & {
type: 'positionedBox',
left: number,
top: number,
}
// is like Box + it has colo
type ColorBox = Box & {
type: 'colorBox',
color: string,
}
const logSize = (obj: Box) => {
console.log({ w: obj.width, h: obj.height });
};
const logPosition = (obj: PositionedBox) => {
console.log({ l: obj.left, t: obj.top });
};
const logColor = (obj: ColorBox) => {
console.log({color: obj.color});
};
// this function should accept any Box like type
const logBox = (obj: Box) => {
logBox(obj);
// $ERROR - obj Box has no type property
// (make sense at some point, but how to avoid it?)
if (obj.type === 'colorBox') logColor(obj);
if (obj.type === 'positionedBox') logPosition(obj);
}
问题是: logBox()
函数声明应该是什么样子才能通过流类型检查。
这些错误是合理的,因为没有什么可以阻止我将 {width: 5, height: 5, type: 'colorBox'}
传递给 logBox
函数,因为它是 Box
的子类型。如果你真的想接受 Box
的任何子类型,你将不得不处理后果,即检查 type
字段不会给你关于任何其他属性的信息。
如果您只想允许 Box
的特定子类型,那么您需要 disjoint union。下面我将 Box
重命名为 BaseBox
并添加了一个单独的 Box
类型,它是两个专用框的联合。这个例子通过了。
type BaseBox = {
width: number,
height: number,
}
// is like Box + it has position
type PositionedBox = BaseBox & {
type: 'positionedBox',
left: number,
top: number,
}
// is like Box + it has colo
type ColorBox = BaseBox & {
type: 'colorBox',
color: string,
}
type Box = PositionedBox | ColorBox;
const logSize = (obj: Box) => {
console.log({ w: obj.width, h: obj.height });
};
const logPosition = (obj: PositionedBox) => {
console.log({ l: obj.left, t: obj.top });
};
const logColor = (obj: ColorBox) => {
console.log({color: obj.color});
};
// this function should accept any Box like type
const logBox = (obj: Box) => {
logBox(obj);
// $ERROR - obj Box has no type property
// (make sense at some point, but how to avoid it?)
if (obj.type === 'colorBox') logColor(obj);
if (obj.type === 'positionedBox') logPosition(obj);
}
我的应用程序中几乎没有几种具有共同属性的类型。我将公共属性抽象为分离类型。现在我想编写一个函数,它接受任何具有共同基类型的类型。
这几行比以下文字更好地解释了问题:
type Box = {
width: number,
height: number,
}
// is like Box + it has position
type PositionedBox = Box & {
type: 'positionedBox',
left: number,
top: number,
}
// is like Box + it has colo
type ColorBox = Box & {
type: 'colorBox',
color: string,
}
const logSize = (obj: Box) => {
console.log({ w: obj.width, h: obj.height });
};
const logPosition = (obj: PositionedBox) => {
console.log({ l: obj.left, t: obj.top });
};
const logColor = (obj: ColorBox) => {
console.log({color: obj.color});
};
// this function should accept any Box like type
const logBox = (obj: Box) => {
logBox(obj);
// $ERROR - obj Box has no type property
// (make sense at some point, but how to avoid it?)
if (obj.type === 'colorBox') logColor(obj);
if (obj.type === 'positionedBox') logPosition(obj);
}
问题是: logBox()
函数声明应该是什么样子才能通过流类型检查。
这些错误是合理的,因为没有什么可以阻止我将 {width: 5, height: 5, type: 'colorBox'}
传递给 logBox
函数,因为它是 Box
的子类型。如果你真的想接受 Box
的任何子类型,你将不得不处理后果,即检查 type
字段不会给你关于任何其他属性的信息。
如果您只想允许 Box
的特定子类型,那么您需要 disjoint union。下面我将 Box
重命名为 BaseBox
并添加了一个单独的 Box
类型,它是两个专用框的联合。这个例子通过了。
type BaseBox = {
width: number,
height: number,
}
// is like Box + it has position
type PositionedBox = BaseBox & {
type: 'positionedBox',
left: number,
top: number,
}
// is like Box + it has colo
type ColorBox = BaseBox & {
type: 'colorBox',
color: string,
}
type Box = PositionedBox | ColorBox;
const logSize = (obj: Box) => {
console.log({ w: obj.width, h: obj.height });
};
const logPosition = (obj: PositionedBox) => {
console.log({ l: obj.left, t: obj.top });
};
const logColor = (obj: ColorBox) => {
console.log({color: obj.color});
};
// this function should accept any Box like type
const logBox = (obj: Box) => {
logBox(obj);
// $ERROR - obj Box has no type property
// (make sense at some point, but how to avoid it?)
if (obj.type === 'colorBox') logColor(obj);
if (obj.type === 'positionedBox') logPosition(obj);
}