你是对的。 Typescript 会给你这个错误,因为它不知道应该考虑哪一种类型shapreRef
as.
IMO 的最佳解决方案是使用类型保护装置 https://www.typescriptlang.org/docs/handbook/advanced-types.html. A 类型保护是检查变量是否属于某种类型的打字稿方法。对于联合类型,这使打字稿能够理解某些东西属于特定类型。
例如,在您的情况下,它可能是这样的:
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
。这意味着打字稿将在这里解释一个真实的返回值,就好像shape
is an IEllipse
.
然后,无论您想在何处使用SvgShape
,您可以检查哪种类型SvgShape
是的,打字稿应该基于此知道类型:
// ...
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="..." />;
}
}
// ...
为什么不只是一个交叉点类型?
嗯...交集类型更适合每种类型(矩形、多边形等)在新项目中具有完全相同的属性的情况。
例如:
type Inter = IRect & IPolygon & IEllipse;
意味着一个Inter
类型是IRect
and IPolygon
and IEllipse
。这意味着该类型的对象将具有所有三种类型的所有成员。
因此,尝试访问该属性points
(存在于IPolygon
)实际上是一个形状IRect
,将表现得好像该属性存在于此(我们不希望如此)
您将主要看到用于混合的交集类型和其他不适合经典面向对象模型的概念。
如何与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;
}