What is the specific purpose of the 'extend' keyword in Typescript?

Recently, I have been delving into the realm of Javascript/Typescript/React as a PHP developer.
During my learning process, I encountered a few perplexing issues that I could not fully grasp.
In light of this, I am reaching out to the experienced individuals here for some guidance.

#1 Creating a Generic Function with Mongoose Model as a Generic Type

Description

I devised a generic function to retrieve all schema properties excluding _id and __v fields.
After several attempts, I managed to get it working. Below is the code snippet:

// model
import mongoose, { Schema, Document } from 'mongoose'

export interface IGenre extends Document {
  name: string,
  description: string,
  createdDate: Date,
  updatedDate: Date
}

const GenreSchema: Schema = new Schema({
  name: { type: String, default: '' },
  description: { type: String, default: '' },
  createdDate: { type: Date, default: Date.now },
  updatedDate: { type: Date, default: Date.now }
})

export default mongoose.models['Genre'] || mongoose.model<IGenre>('Genre', GenreSchema)

// generic function returning props of model
import { Model } from 'mongoose'

const getSchemaProps = <S extends Model<S>>(s: S): string[] => {
  return Object.keys(s.schema.paths).filter(p => p !== '_id' && p !== '__v')
}

export {
  getSchemaProps,
}

Unclear Concept

The part that puzzles me is <S extends Model<S>>.
Aren't we creating some sort of loop here?
My understanding is that S extends Model, but the S inside Model also extends Model, resulting in

S extends Model<S extends Model<S....>>

I did not search Google for an explanation, just experimented randomly and it surprisingly worked without any errors!

Inquiry

Why does this particular line of code not raise an error?

<S extends Model<S>>

#2 Extending Types with Assigned Values

Description

While browsing through the type definition file of a Material UI component, I stumbled upon a syntax that left me baffled.

// <system_path>\node_modules\@mui\x-data-grid\models\colDef\gridColDef.d.ts
export declare type GridColumns<R extends GridValidRowModel = any> = GridEnrichedColDef<R>[]

The definition of GridValidRowModel can be found below in this same file:

// <system_path>\node_modules\@mui\x-data-grid\models\gridRows.d.ts
export declare type GridValidRowModel = {
    [key: string]: any;
};

Confusion

Upon reading the TypeScript documentation, I was unable to find an explanation for the following syntax:

GridColumns<R extends GridValidRowModel = any> // (1)

If I were to hazard a guess, the GridValidRowModel = any part assigns a default type of any to GridValidRowModel, making (1) equivalent to this:

GridColumns<R extends any>

However, in gridRows.d.ts, GridValidRowModel is clearly defined as an object with key-value properties.

Question

What exactly does this syntax signify?

ISomeInterface<T extends A = B>

In the given code snippet, what type of R is being referred to?

Answer №1

Incorrect generics parsing - I emphasized with parentheses

Original interpretation:

ISomeInterface<T extends (A = B)>

Actual Typescript interpretation:

ISomeInterface<(T extends A) = B>

This means that:

GridColumns<R extends GridValidRowModel = any>

is the same as:

GridColumns<any>

Keep in mind that 'any' doesn't represent an empty object, but rather something that can meet any class checks - 'any' can extend everything!

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

Is it possible to efficiently structure intricate JSON data onto interfaces in TypeScript with the incorporation of observables?

I am currently working on creating a simple web news reader that relies heavily on the Google News API (). I have set up all the necessary services, models, etc. However, I am having difficulty mapping the data onto specific interfaces. The Google API retu ...

Avoid selecting primary key column in TypeORM查询

Is it possible to exclude primary key columns from being selected in TypeORM? I've tried using the select false option, but it doesn't seem to work for these specific columns. Could it be because they are essential for identifying the entity or b ...

Angular5 causing all divs to have click events at once instead of individually triggered

I am a beginner when it comes to working with Angular and I have encountered an issue. I created a click event on a FAQ page in Angular 5, but the problem is that when I click on one FAQ, they all open up instead of just the targeted one. Here is my TypeS ...

The disappearance of the "Event" Twitter Widget in the HTML inspector occurs when customized styles are applied

Currently, I am customizing the default Twitter widget that can be embedded on a website. While successfully injecting styles and making it work perfectly, I recently discovered that after injecting my styles, clicking on a Tweet no longer opens it in a ne ...

Leverage glob patterns within TypeScript declaration files

Utilizing the file-loader webpack plugin allows for the conversion of media imports into their URLs. For example, in import src from './image.png', the variable src is treated as a string. To inform TypeScript about this behavior, one can create ...

Is there a way to remove specific Material UI css styles from a ListItem component?

Currently, I am working with the ListItem component from Material-UI and I need to remove the preset background color it has. Despite my attempts using classes, the default value keeps taking precedence. Can someone please advise on how to turn off this ...

Troubleshooting native web worker issues in Angular 11 - Addressing the Element Bug

After upgrading Angular to version 11, I encountered issues with utilizing web workers for heavy data processing in my project. Previously, I used webworkify-webpack (https://www.npmjs.com/package/webworkify-webpack), but it stopped working post-migration. ...

The intersection of conditional types and the combination of string literals with class unions

Encountered an unusual behavior in the types system when trying to type the as prop from emotion. import React, { Component, FC, PropsWithChildren } from "react"; // Defining possible types for `as` prop type AsType = | keyof JSX.IntrinsicElements | ...

Sending data from an element within an ngFor loop to a service module

In my component, I have a loop that goes through an array of different areas with unique IDs. When you click the button, it triggers a dialog containing an iframe. This iframe listens for an event and retrieves data as JSON, then sends it via POST to an IN ...

Tips for programmatically focusing on a v-textarea using Vuetify and TypeScript

It feels impossible right now, I've attempted some unconventional methods like: (this.refs.vtextarea as any).textarea.focus() ((this.refs.vtextarea as Vue).$el as HTMLElement).focus() and so on... Javascript source code is quite complex for me to ...

Animate the transition between the icon and extended variant in Material-UI FAB

If you have a Material-UI FAB with the following code: <Fab size="medium" color="primary" aria-label="add"> <AddIcon /> </Fab> And you want to toggle to this other state: <Fab var ...

Angular 2 Typescript: Understanding the Structure of Member Properties and Constructors

I am currently exploring a project built with Ionic 2, Angular 2, and Typescript, and I find myself puzzled by the way member properties are being set. In the code snippet below, I noticed that Angular automatically injects dependencies into the construc ...

What is the best way to organize my NPM package with separate directories for types and functions?

I am currently working on developing a custom NPM package that will serve as a repository for sharing types and functions across my project. Let's name this project wordle. Given the emphasis on types, it is worth noting that I am using TypeScript for ...

Navigating through React with Typescript often involves managing the process of waiting for an API call to finish

My interface structure is as follows: export interface Chapter{ id: string, code: string } Within a component, I am making an API call in the following manner: componentDidMount() { fetch("https://someapi/getchapter") .then(r ...

ngRepeat momentarily displays duplicate items in the list

There is a modal that appears when a button is clicked. Inside the modal, there is a list of items that is populated by data from a GET request response stored in the controller. The issue arises when the modal is opened multiple times, causing the list t ...

Filling a data entry with simultaneous commitments

Sample code: type Alphabet = 'a' | 'b' | 'c'; const alphabetMap: Record<Alphabet, null> = { 'a': null, 'b': null, 'c': null} // Select any asynchronous processing function you prefer funct ...

JavaScript/Typescript is throwing an error because it is unable to access the property 'username' of an undefined object

In my project, I am attempting to compile a list of Profile objects and then extract specific elements from each object in the list. To accomplish this, I have defined a public interface named Profile, imported it into my component, and instantiated a new ...

unable to connect a value with the radio button

I am struggling to incorporate a radio group within a list of items. I am facing difficulty in setting the radio button as checked based on the value provided. Can anyone provide me with some guidance? Here is the HTML code snippet: <div *ngFor=" ...

What is the appropriate directory to place the `typescript` package in order for WebStorm to recognize it?

According to the information on this webpage: The Configure TypeScript Compiler dialog box provides two options: Detect: WebStorm will look for a typescript package within the current project. If it finds one, it will use that package. Otherwise ...

What kind of Typescript type should be assigned to setState when passed to the component?

In my setup, I have a variety of Parent components: const ParentOne = () => { const [error, setError] = useState<{ one: boolean }>({ one: false }); ...omit return ( <> <Child setErr={setError} name={"one"} /> </> ...