Вы правы.Typescript дает вам эту ошибку, потому что он не знает, какой из типов должен учитывать shapreRef
как.
Лучшее решение IMO использует Type Guards .A Type Guard - это машинописный способ проверки, относится ли переменная к определенному типу.Для объединяемых типов это дает типизированному представлению понимание того, что что-то имеет определенный тип.
Например, в вашем случае это может быть что-то вроде этого:
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
было 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="..." />;
}
}
// ...
Почему бы не просто тип пересечения?
Ну ... Типы пересечения больше подходят для случаев, когдакаждый из типов (Rect, Polygon и т. д.) имеет одинаковые атрибуты в новом элементе.Например:
type Inter = IRect & IPolygon & IEllipse;
Означает, что тип Inter
имеет тип IRect
и IPolygon
и 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;
}