你是对的。typescript给你这个错误,因为它不知道它应该将哪一种类型考虑在内shapreRef
。
IMO 的最佳解决方案是使用Type Guards。一类保护是检查是否一个变量是某种类型的typescript方式。对于联合类型,这让 typescript 理解某些东西属于特定类型。
例如,在您的情况下,它可能是这样的:
interface IEllipse {
attr1: string;
attr2: string;
}
interface IRect {
attr3: string;
attr4: string;
}
type SvgShape = IEllipse | IRect | IPolygon;
function isEllipse(shape: SvgShape): shape is IEllipse {
return (shape as IEllipse).attr1 !== undefined;
}
请注意,返回类型是shape is IEllipse
. 这意味着typescript将在这里解释一个真实的返回值,就好像shape
是一个IEllipse
.
然后,无论您想在何处使用 a SvgShape
,您都可以检查SvgShape
它是哪种类型,并且typescript应该基于此知道类型:
// ...
render() {
const shape: SvgShape = this.getCurrentShape();
if (isEllipse(shape)) {
// typescript should KNOW that this is an ellipse inside this if
// it will accept all of Ellipse's attribute and reject other attributes
// that appear in other shapes
return <ellipse .../>;
} else if (isRect(shape)) {
// typescript should interpet this shape as a Rect inside the `if`
return <rect ... />;
} else {
// typescript will know only one subtype left (IPolygon)
return <polygon points="..." />;
}
}
// ...
为什么不只是一个 Intersection 类型?
嗯...交集类型更多用于每种类型(矩形、多边形等)在新项目中具有完全相同的属性的情况。例如:
type Inter = IRect & IPolygon & IEllipse;
意味着一个Inter
类型是IRect
和IPolygon
和IEllipse
。这意味着这种类型的对象将具有所有三种类型的所有成员。因此,尝试访问实际上是 的形状points
上的属性(存在于 上IPolygon
)IRect
将表现得好像该属性存在于那里(我们不想要)
您将主要看到用于 mixin 和其他不适合经典面向对象模型的概念的交集类型。
如何与 useRef 一起使用?
type SvgShape = SVGPolygonElement | SVGEllipseElement | SVGRectElement;
const shapeRef = useRef<SvgShape>(null);
function isEllipseRef(shapeRef: MutableRefObject<SvgShape>): shapeRef is MutableRefObject<IEllipse> {
const shape: SvgShape = shapeRef.current;
return (shape as IEllipse).attr1 !== undefined;
}