I've run into an issue with typing React components that I've never run into before. I've simplified the issue below.
interface Circle {
kind?: "circle";
radius: number;
}
interface Square {
kind: "square";
sideLength: number;
}
type Shape = Circle | Square;
const shape: Shape = {
sideLength: 7,
radius: 7,
};
Link to TypeScript Playground containing the above
In the example above, I'd expect the shape
variable declaration to throw an error in TypeScript as neither a Circle nor a Square have both a sideLength
and a radius
. The defined object is neither a Circle nor a Square, so in my eyes it shouldn't be a valid shape.
Is it possible to define the types in such a way that the following items will be valid or errors (as labelled).
// Valid
const shape: Shape = {
kind: 'circle',
radius: 7,
};
// Valid
const shape: Shape = {
radius: 7,
};
// Valid
const shape: Shape = {
kind: 'square',
sideLength: 7,
};
// Error
const shape: Shape = {
sideLength: 7,
radius: 7,
};
// Error
const shape: Shape = {
sideLength: 7,
};
// Error
const shape: Shape = {
kind: 'square',
radius: 7,
};
// Error
const shape: Shape = {
kind: 'circle',
sideLength: 7,
};
EDIT:
For further clarification, in my use-case kind
is optional on a Circle. For those familiar with React the actual problem I'm trying to solve is around the as
property exposed by styled-components. I want a component to accept an optional as
prop which will allow the user to change the component (by-default a button
) to a link (a
). If the user specifies as="a"
then I want TypeScript to compalin if the user then tries to use button-specific props on what is now a link (disabled
, for example). The as
prop is optional as I don't want all implementors to be required to pass it. In my simplified example above as
is analagous to kind
, hence why kind
is optional.