``Should one prioritize the use of Generics over Inheritance, or is there a better way

We are currently in the process of implementing new contracts for our icons system, and we have encountered a debate on which approach is more preferable. Both options result in the same interface:

Using Generics -> Although the interface may be less clear, we benefit from auto-complete and compilation errors with zero effort once the type property is defined.
Not Using Generics -> Developers will need to manually specify 'as AccountIcon' (or another type) for any object that expects to receive an Icon.

Example of Inheritance

export interface Icon {
  type: 'account' | 'img' | 'font-icon';
}

export interface AccountIcon extends Icon {
  readonly type: 'account';
  value: LinkIcon<LinkIconType>;
}
export interface ImgIcon extends Icon {
  readonly type: 'img';
  value: Icon;
}
export interface FontIcon extends Icon {
  readonly type: 'font-icon';
  value: string;
}

Example of Generics

export interface FilterIcon<T extends IconType> {
  readonly type: T;
  value: T extends 'account' ? LinkIcon<LinkIconType> : T extends 'font-icon' ? string : Icon;
}

export type IconType = 'font-icon' | 'img' | 'account';

Answer №1

One effective approach would be to use a discriminated union in this scenario.

export interface AccountIcon {
  readonly type: 'account';
  value: LinkIcon<LinkIconType>;
}

export interface ImgIcon {
  readonly type: 'img';
  value: IconValue;
}

export interface FontIcon {
  readonly type: 'font-icon';
  value: string;
}

export type Icon = AccountIcon | ImgIcon | FontIcon;

This design aligns with your specific needs - accommodating various types of icons while allowing for general processing without requiring knowledge of the exact type.

An important benefit here is that TypeScript can intelligently infer the type when evaluating conditions based on the icon's type:

if (icon.type === 'img') {
  // TypeScript recognizes icon as an ImgIcon 
} else {
  // TypeScript identifies that icon is not an ImgIcon.
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Upon running `npm run build` in vue.js, an error occurs stating that the interface 'NodeRequire' cannot extend types 'Require' simultaneously

ERROR in C:/phpStudy2018/PHPTutorial/WWW/Tms.Web/node_modules/@types/node/globals.d.ts(139,11): 139:11 The 'NodeRequire' interface cannot extend both 'Require' and 'RequireFunction' at the same time. The named property &apos ...

The method base() in Java generics is not defined for type T

I'm diving into the concept of generics in Java and attempting to work on a simple example. However, I'm facing an issue where it keeps coming back with an error message: Exception in thread "main" java.lang.Error: Unresolved compilation probl ...

Tips for determining the defaultValue type in React.context usage

'use client'; import { useState, createContext, useMemo } from 'react'; type MessageStatus = 'default' | 'success' | 'error'; export type MessageProps = { type: MessageStatus; payload: string; }; ty ...

Updating an object within an array of objects in Angular

Imagine having a unique object array named itemArray with two items inside; { "totalItems": 2, "items": [ { "id": 1, "name": "dog" }, { "id": 2, "name": "cat" }, ] } If you receive an updated result for on ...

What is the process for creating an additional username in the database?

As a beginner frontend trainee, I have been tasked with configuring my project on node-typescript-koa-rest. Despite my best efforts, I encountered an error. To set up the project, I added objection.js and knex.js to the existing repository and installed P ...

The 'picker' property is not found in the '{}' type but is necessary in the 'TimeRangePickerProps' type

I am encountering an issue while trying to implement the new RangePicker for the TimePicker of antd v4. Surprisingly, this error only occurs in my development environment and not when I try to reproduce it on codesandbox. Despite checking their documentati ...

Retrieve the attribute from a TypeScript union data type

Here is the structure that I am working with: export interface VendorState extends PaginationViewModel { vendors: CategoryVendorCommand[] | CategoryVendorCommand; } This is my model: export interface CategoryVendorCommand { id: string; name: str ...

Angular searchbar issue: Unable to assign parameter of type 'unknown' to parameter of type 'string'

I've been working on an Angular app to fetch data from an API successfully. However, I'm currently facing a challenge while implementing a search function in my component.ts file. Here is the entire service code: import { Injectable } from &apos ...

The error message "Property '...' is not found on the type 'ServerContextJSONValue'" pops up whenever I try to utilize the useContext() function

After creating a Provider and defining the type, I encountered a TypeScript error when using it with useContext(): "Property '...' does not exist on type 'ServerContextJSONValue'. I'm not sure what I am missing. Can anyone help me ...

Setting an optional property to null is not permitted

In my model class, I have defined an optional property as follows: export class Workflow { constructor( public id: number, public started: Date, public documentId: number, public document: Document, public status: WorkflowStatus, ...

Template URI parameters are being used in a router call

Utilizing the useRouter hook in my current project. Incorporating templated pages throughout the application. Implementing a useEffect hook that responds to changes in the router and makes an API call. Attempting to forward the entire URL to /api/${path ...

Utilizing a method from a separate class in Ionic 2

Having trouble using the takePicture() function from camera.ts in my home.ts. I keep getting an error message saying "No provider for CameraPage!" Any assistance on how to resolve this issue would be greatly appreciated, as I am new to this language and ju ...

The state update is triggering a soft refresh of the page within Next.js

In my Next.js project, I have integrated a modal component using Radix UI that includes two-way bound inputs with state management. The issue arises when any state is updated, triggering a page-wide re-render and refreshing all states. Here is a snippet of ...

Using React and TypeScript together can lead to issues when trying to use union keys as an index

I've implemented a hook using useState and the delete method to effectively manage my form values. const [values, setValues] = useState<tAllValues>({}); The values stored include: { name: 'Andrew', age: 34, avatar: [{ name: ...

The TypeScript type for a versatile onChange handler in a form

Let's skip the function declaration and dive into writing the current types for state, and the state itself. type BookFormState = { hasError: boolean; } BookForm<BookFormState> { ... state = { hasError: false }; Next, inside the class ...

Switch from Gulp-TSLint to Gulp-ESLint for enhanced code analysis!

I am currently in the process of updating a Gulp task that uses gulp-tslint to now use gulp-eslint. The code snippet below outlines the changes I need to make: const { src } = require('gulp'); const config = require('./config'); const ...

The Console.log function first displays an Object, and then changes to display an Array containing a single object when clicked

When I utilize MobX to call an observable within my React component, something peculiar happens. Upon console logging the observable, initially it appears as an Object. However, upon clicking on it, the object transforms into an Array for that one particul ...

What is the correct way to specify type hints for a Stream of Streams in highlandjs?

I'm currently working with typescript@2 and the highlandjs library. In the typings for highland, there seems to be a missing function called mergeWithLimit(n). This function: Accepts a Stream of Streams, merges their values and errors into a single ...

Typescript's interface for key-value pairing with generic types

Consider the example Object below: let obj1: Obj = { 'key1': { default: 'hello', fn: (val:string) => val }, 'key2': { default: 123, fn: (val:number) => val }, // this should throw an error, because the types of d ...

Listening to changes in a URL using JQuery

Is there a way to detect when the browser URL has been modified? I am facing the following situation: On my webpage, I have an iframe that changes its content and updates the browser's URL through JavaScript when a user interacts with it. However, no ...