I have this interface:
export interface AlertInteraction<T> {
id: AlertId;
data: T;
buttonId: AlertButtonId;
}
But there are times where data is not needed. I know I can declare it as data: T
but I would like to know if I could something like this:
export interface AlertInteraction<T> {
id: AlertId;
data: T;
buttonId: AlertButtonId;
}
export interface AlertInteraction {
id: AlertId;
buttonId: AlertButtonId;
}
So, if I give T
then I assume I want to access the data, if no then assume it does not exist. Is it possible?
Like classes, interfaces also can be generic. A generic interface has generic type parameter list in an angle brackets <> following the name of the interface: interface interfaceName<T> { // ... } This make the type parameter T visible to all members of the interface.
A generic interface has generic type parameter list in an angle brackets <> following the name of the interface: interface interfaceName<T> { // ... } Code language: TypeScript (typescript) This make the type parameter T visible to all members of the interface. The type parameter list can have one or multiple types. For example:
Summary: in this tutorial, you will learn how to develop TypeScript generic interfaces. Like classes, interfaces also can be generic. A generic interface has generic type parameter list in an angle brackets <> following the name of the interface:
The rules of inheritance that apply to classes also apply to interfaces: Generic interfaces can inherit from non-generic interfaces if the generic interface is covariant, which means it only uses its type parameter as a return value.
In order to achieve that we need to use conditional types.
type AlertId = string; // just example type alias
type AlertButtonId = string; // just example type alias
type AlertInteraction<T = undefined> = {
id: AlertId;
buttonId: AlertButtonId;
} & (T extends undefined ? {} : {
data: T;
})
// example usage
// no need for data (T is undefined)
const a: AlertInteraction = {
id: '1',
buttonId: '1'
}
// data prop is required
const b: AlertInteraction<number> = {
id: '1',
data: 1,
buttonId: '1'
}
Most important is this part:
& (T extends undefined ? {} : {
data: T;
})
We join conditionally or type {}
if T is assignable to undefined, or we join {data: T}
for other type. In result if we don't set the generic, it is by default undefined
and our type constructor computes into:
// For T == undefined
{
id: AlertId;
buttonId: AlertButtonId;
} & {}
// what is equal to just:
{
id: AlertId;
buttonId: AlertButtonId;
}
For a case where argument(generic) is provided as something different then undefined
, then the final type has a form:
// For T != undefined
{
id: AlertId;
buttonId: AlertButtonId;
} & { data: T}
// which is equal to
{
id: AlertId;
buttonId: AlertButtonId;
data: T;
}
Where T
is type given by argument of type constructor. To also clear the information - Type constructor = any type definition with an generic argument.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With