Reputation: 1011
I want to write a type that allows for object creation with some core properties that are always required and an optional property imageUrl
which when defined as a string means imageAltText
is also required as a string,
{
id: "test",
imageUrl: "test",
imageAltText: "test"
}
I also want it to work so that when imageUrl
is not defined I do not expect imageAltText
to be defined.
{
id: "test"
}
I've defined the type as the following,
(
{
/** image url for the banner of the card. Will display a blue background without an image */
imageUrl?: undefined;
}
|
{
/** image url for the banner of the card. Will display a blue background without an image */
imageUrl: string;
/** alternative text for the banner image */
imageAltText: string;
}
)
However, by making `imageUrl` optional `?` typescript allows me to write `imageAltText` even when `imageUrl` is undefined.
Upvotes: 5
Views: 1024
Reputation: 25966
type ForbidProps<T> = {
[P in keyof T]?: never;
}
type OptionalImagePart = {
imageUrl: string;
imageAltText: string;
}
type Image = { id: number; } & (OptionalImagePart | ForbidProps<OptionalImagePart>)
const image1Ok: Image = {
id: 1
}
const image2Ok: Image = {
id: 1,
imageUrl: 'imageUrl',
imageAltText: 'imageAltText'
}
const image3Error: Image = { // Expected error
id: 1,
imageUrl: 'imageUrl'
}
const image4Error: Image = { // Expected error
id: 1,
imageAltText: 'imageAltText'
}
Upvotes: 3
Reputation: 33051
Here you have:
type RequiredParams<T = {}> = {
id: string
} & T
type UnionParams =
| RequiredParams<{ imageUrl: string; imageAltText: string; }>
| RequiredParams
type UnionKeys<T> = T extends T ? keyof T : never;
type StrictUnionHelper<T, TAll> =
T extends any
? T & Partial<Record<Exclude<UnionKeys<TAll>, keyof T>, never>> : never;
type StrictUnion<T> = StrictUnionHelper<T, T>
type Result = StrictUnion<UnionParams>
const a: Result = { id: 'sdf' }; // ok
const b: Result = { id: 'sdf', imageUrl: 'sdf', imageAltText: 'sdf' } // ok
const c: Result = { id: 'sdf', imageUrl: 'sdf' } // error
const d: Result = { id: 'sdf', imageAltText: 'sdf' } // error
All gredits goes to @Titian Cernicova-Dragomir
Upvotes: 3