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

Keying objects based on the values of an array

Given the array: const arr = ['foo', 'bar', 'bax']; I am looking to create an object using the array entries: const obj = { foo: true, bar: true, bax: false, fax: true, // TypeScript should display an error here becau ...

Implementing Service Communication

I created an Angular Application using the Visual Studio Template. The structure of the application is as follows: /Clientapp ./app/app.module.shared.ts ./app/app.module.client.ts ./app/app.module.server.ts ./components/* ./services/person-data.service. ...

Having Trouble Showing Loading Component on Next.js v13

Having some issues with setting up a loading component in my Next.js v13 project. I followed the documentation by creating a file called loading.tsx in the src directory, but it's not appearing on the page as expected. I've also included a functi ...

The type 'MenuOptions[]' cannot be assigned to type 'empty[]'

Even after numerous attempts, I am still grappling with TypeScript problems. Currently, I am at a loss on how to resolve this particular issue, despite all the research I have conducted. The code snippet below is what I am working with, but I am struggling ...

Assigning value to a member variable in a TypeScript Angular class

Currently, I am in the process of learning Angular. To enhance my skills, I am developing a simple web application using Angular and Spring Boot. One challenge I encountered is assigning a variable to the member variable of a Class. import { Injectable } f ...

Transforming an array into an object using TypeScript

I am attempting to create a generic type for a function that transforms an array into an object, like so: type ObjectType = { id: number; name: string; status: string }; const xyz: ObjectType[] = [ { id: 1, name: "X", status: " ...

Enhanced VS code typings for Nuxt injected properties

My approach to injecting properties into the Nuxt TS context is as follows: ~/plugins/services.ts import Vue from 'vue'; import { errorService } from '~/services/error'; import { Plugin } from '@nuxt/types' const services: Pl ...

How can I utilize a filter or pipe to populate product categories onto screens within Ionic 2?

I am considering creating an Ionic 2 app with 6 pages, but I'm unsure whether to utilize a Pipe or a Filter for the individual category pages and how to implement the necessary code. Each category page should be able to display products from the "app ...

React-dnd enabling drag-and-drop functionality with Mui DataGrid

Previously, I had experience working with a mui treeview that was easy to expand using react-dnd since each treeitem was a react component. However, when it comes to a datagrid, the rows are made up of JSON objects and not react components anymore. Is the ...

"Exploring the world of Typescript with the Drawflow library

Currently, I am integrating the fantastic Drawflow library created by @Jerosoler (available at: https://github.com/jerosoler/Drawflow) into my PrimeNg project. User @BobBDE has provided typescript definitions for this library here: https://www.npmjs.com/p ...

Incorporate a Home page link within the AppBar using Material-UI

Just getting started with React and I'm looking to insert a link to the "Home" page in the AppBar component of Material-UI (version 4.0.1). The desired behavior is that when the "Home" link is clicked, the "OnePage" component should be displayed. Wit ...

Unraveling the mysteries of an undefined entity

When the variable response is undefined, attempting to retrieve its property status will result in an error: Error: Unable to access property 'status' of undefined const { response, response: { status }, request, config, } = error as A ...

Reveal the class to the global scope in TypeScript

ClassExample.ts: export class ClassExample{ constructor(){} } index.html: <script src="ClassExample.js"></<script> // compiled to es5 <script> var classExample = new ClassExample(); //ClassExample is not defined < ...

Nestjs: Accessing the request or context using a Decorator

In my current project using NestJS, I am attempting to make the executionContext accessible in a logger for the purpose of filtering logs by request. Each injectable has its own instance of a logger, and I want to maintain this setup (where the scope of t ...

Issue with rendering Chip component in MUI within React upon initial click

Utilizing MUI Select for multi-select options and displaying the modified final values as MUI Chips. However, I encountered an issue where the chip does not show instantly when adding but appears upon rendering the page after modifying the name or suffix ...

The Material UI textfield is not resetting after a change in state

Could someone help me figure out why my simple Text field is not clearing when a button is pressed? I am passing the state as a value to the textfield and changing the state, but the field remains filled... Check out the sandbox here export default functi ...

Is there a way to denote a specific part of a generic type without explicitly specifying the parts as generics themselves?

My dilemma involves an object defined by a type from a 3rd party library: // Unable to modify this - it belongs to the 3rd party library; interface TypedEvent< TArgsArray extends Array<any> = any, TArgsObject = any > extends Event { args ...

Selecting logic depending on the request body in NestJS

Currently, my controller looks like the following: @Controller("workflow") export class TaskWorkflowController { public constructor( private readonly jobApplicationActivityWorkflow: JobApplicationActivityService ) {} @Post("/:job- ...

The side menu fails to appear when pressed

When using the push method, I am unable to see the side menu. However, it works fine with the setRoot navigation. How can I resolve this issue and display the side menu when using the push method? dashboard.html <ion-col col-9> <ion-searchbar ...

Guide to customizing the layout preview specifically for certain components in Storybook, without affecting all components

Currently working on my storybook project and facing an issue. I'm aiming to have the layout centered in the preview section. I attempted export const parameters = { layout: 'centered', }; in the .storybook/preview.js file However, this c ...