Encountering difficulty utilizing Partial with a generic type

I'm currently working on developing a class called Map that will store mappings set by other classes, such as CharacterManager.
I want the content of the map to be determined by other classes, so I have designed the Map class to accept a generic type that will always extend from object.

For instance:

// Map.ts
interface MapCellData {
  collides: boolean;
}

class Map<CellData extends object = {}> {
  map!: Array<Array<CellData & MapCellData>>;
}

// CharacterManager.ts
interface CharacterManagerCellData {
  character: null | Character;
}

// Other interfaces...

When examining the type

Array<Array<CellData & MapCellData>>
, the intention is for each cell of the 2D array to contain multiple properties defined by various classes.

However, the problem arises when I have to provide those properties during the initial population of the map.
This does not align with my approach: I prefer the Map class to remain unaware of what other classes intend to add. Each class should be responsible for supplying its own data, with the Map class handling the initialization of the map initially so it is accessible to others.

The straightforward solution, in my mind, is to make the CellData properties optional since they are not set when populating the map for the first time. Any class wanting to utilize it should confirm whether it is set.

Following this logic, I updated

Array<Array<CellData & MapCellData>>
to
Array<Array<Partial<CellData & MapCellData>>>
(by adding the Partial keyword).

Now, the actual issue arises: despite this adjustment, the code does not function as expected, and I am not getting any error details to pinpoint my mistake.
TypeScript simply indicates

Type '{ collides: true; }' is not assignable to type 'Partial<CellData & MapCellData>'.

Below is a complete example that triggers the error:

interface CharacterManagerCellData {
  character: null | string;
}

interface CollisionCellData {
    collides: boolean;
}

// Using partial without a generic works correctly
type BasicCellData = Partial<CharacterManagerCellData & CollisionCellData>;

const myCell: BasicCellData = {
  collides: true
}

// Applying the same pattern with a generic results in a TypeScript error
function myFunc<CellData extends object = {}>() {
  type RealCellData = Partial<CellData & CollisionCellData>;

  const cell: RealCellData = {
    collides: true
  }
}

I am using the latest version of TypeScript (3.6.3), and this error persists in the playground

Answer №1

It is important to note that TypeScript does not allow assigning a concrete value to a generic type, as shown in the example below:

myFunc<{ collides: false }>()

In this example, the value of collides should be false based on the defined type, but it is incorrectly initialized as true. This violates the principle that a generic function should be valid for any given T. In cases where TypeScript cannot determine the final type of a property, simple assignments are not allowed:

// Valid assignment
function myFunc<CellData extends CollisionCellData >() {
  type RealCellData = Partial<CellData>;

  const cell: RealCellData = { 
     collides: true
  } 
  cell.collides = true; // This is allowed because TS knows 'collide' is boolean
}

// Invalid assignment
function myFunc<CellData extends object >() {
  type RealCellData = Partial<CellData & CollisionCellData>;

  const cell: RealCellData = { 
     collides: true
  } 
  cell.collides = true; // This is not allowed, as TS cannot determine if 'CellData' has 'collides'
}

For cases where you are willing to accept inconsistencies in types, you can use a type assertion:

const cell = {
  collides: true
} as RealCellData

Learn more about TypeScript restrictions and workarounds by running the code in the TypeScript playground.

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

The module imported by Webpack appears to be nothing more than a blank

I am attempting to integrate the "virtual-select-plugin" library into my Typescript project using webpack. Unfortunately, this library does not have any type definitions. Upon installation via npm, I encountered the following error in the browser: TypeErro ...

Tips on using Visual Studio Code to troubleshoot Angular 4 unit tests

I am working on an Angular 4 project with Material design in Visual Studio Code. The setup is done using angular/cli. Currently, I have been writing unit tests using Karma and Jasmine. However, when trying to debug the tests by setting breakpoints, it doe ...

Can you explain the distinction between declaring type using the colon versus the as syntax?

Can you explain the variation between using the : syntax for declaring type let serverMessage: UServerMessage = message; and the as syntax? let serverMessage = message as UServerMessage; It appears that they yield identical outcomes in this particular ...

Exploring Model Object Properties with ngFor in Angular

Currently, I am developing an Angular application with a Model object that consists of properties of various types. My goal is to loop through these properties in the component and generate form fields for each property. Unfortunately, the implementation i ...

What measures can I take to ensure TypeScript transpiles prototype methods effectively?

Having some issues defining methods on a TypeScript class and then accessing them. Even though the methods are defined, it's giving an error that they don't exist. TypeScript: export class ColumnHeader extends JSONObject { // ... i ...

Angular's Integration with PayPal for Shipping Costs

I am facing an issue with my e-commerce website where the receipt only displays the total payment of the items purchased. I have searched for an SDK that supports Angular or TypeScript PayPal integration, but could only find one for JavaScript which did ...

Reacting to the surprise of TS/JS async function behaving differently than anticipated

It appears that I'm facing a challenge with the small method; not sure if my brain is refusing to cooperate or what's going on. async fetchContacts() { await this.http.get('http://localhost:3000/contacts') .subscribe(res =& ...

Dealing with 'TypeError X is Not a Function' Error in Angular (TypeScript): Occurrences in Certain Scenarios and Absence in Others

Recently, I came across an odd issue in Angular 14 where a type error kept popping up. Although I managed to refactor the code and find a workaround, I'm quite intrigued as to why this issue is happening so that I can prevent it from occurring again i ...

Firebase authentication link for email sign-in in Angularfire is invalid

Currently, I am utilizing the signInWithEmailLink wrapper from AngularFire for Firebase authentication. Despite providing a valid email address and return URL as arguments, an error is being thrown stating "Invalid email link!" without even initiating any ...

Experiencing difficulties establishing a connection with my NodeJs server socket and TypeScript

I've been struggling to run the code from this post and I really need some help. The code can be found at: https://medium.com/@mogold/nodejs-socket-io-express-multiple-modules-13f9f7daed4c. I liked the code as it seems suitable for large projects, but ...

What steps can be taken to resolve the error message "How can you repair 'Cannot read properties of undefined (reading 'front_default')'?"

I'm encountering an issue while trying to display data from an API. Although I am able to access the data, a perplexing error keeps popping up that I can't seem to troubleshoot. Here's the error message: Uncaught TypeError: Cannot read pr ...

When attempting to utilize expo-av in a React-Native project on iOS, the recorded MP4 file encountered an issue when trying to submit it as form data for Open

I've been working tirelessly through the night, trying to record myself on my iPhone using expo-av to capture speech and then upload it to openai's transcriptions endpoint with the whisper-1 model. The recording is saved as an mp4 file, which I ...

Supertest and Jest do not allow for sending JSON payloads between requests

Below is the test function I have written: describe("Test to Create a Problem", () => { describe("Create a problem with valid input data", () => { it("Should successfully create a problem", async () => { const ProblemData = { ...

Converting a JSON array stored in a local file to a TypeScript array within an Angular 5 project

I'm currently working on developing a web app using Angular 5. My JSON file has the following structure: [ { "id": 0, "title": "Some title" }, { "id": 1, "title": "Some title" }, ... ] The JSON file is store ...

What is the proper way to define a new property for an object within an npm package?

Snippet: import * as request from 'superagent'; request .get('https://***.execute-api.eu-west-1.amazonaws.com/dev/') .proxy(this.options.proxy) Error in TypeScript: Property 'proxy' is not found on type 'Super ...

Changing the Angular 5 ng-bootstrap Modal Dialog template dynamically in real-time

I'm currently developing a modal dialog that requires the ability to dynamically change the templateURL. The code shown is the default template, but I need to be able to swap it out dynamically. I'm unsure of how to achieve this, as the templateU ...

cssclassName={ validatorState === RIGHT ? 'valid' : 'invalid' }

Is there a way to dynamically add different classes based on validation outcomes in React? My current implementation looks like this: className={ validatorState === RIGHT ? 'ok' : 'no' } However, I also need to handle cases where the ...

Array filtering functions similarly to marketplace filtering tools

In order to make the filter function like a marketplace filter, I want to only see items related to the selected brand and status. For example: partners = [ 0:{ year: "2022" badge_status: "badge-success" sale_date: "01/07/2022&quo ...

Setting null for HttpParams during the call

I am encountering an issue with HttpParams and HttpHeaders after upgrading my project from Angular 7 to Angular 8. The problem arises when I make a call to the API, as the parameters are not being added. Any assistance in resolving this matter would be gre ...

Declaring types globally in Visual Studio Code for JavaScript programming

My /typings/$app.d.ts file has the following structure: declare class App { test: object } export const $app: App; https://i.sstatic.net/3HW7M.png In order to enable intellisense, I have to auto-import it, resulting in a line like this at the begin ...