Provide a definition for constraining type parameters in the inclusion of static methods

Is it possible to set type parameter restrictions for a serializer where the type must have a specific static member or implement an interface "statically"?

For example:

function getStuff<T>(...) -> T {
  T.buildFormJson(getStuffJson(...))
}

Here, buildFromJson is a function(input: Object): T

Can a constraint be established for T to only allow types that include this defined static member?

Answer №1

Reference: https://github.com/microsoft/TypeScript/issues/13462#issuecomment-275860898

interface JsonDeserializable<T> {
  fromJson(obj: Object): T;
}
interface JsonSerializable {
  toJson(): Object;
}

How to use:

import * as assert from "assert";

class Point2D {
  x: number;
  y: number;

  constructor(x: number, y: number) {
    this.x = x;
    this.y = y;
  }

  toJson(): Object {
    return this;
  }

  static fromJson(obj: Object): Point3D {
    return new Point3D(obj['x'], obj['y'], obj['z']);
  }
}

class Point3D {
  x: number;
  y: number;
  z: number;

  constructor(x: number, y: number, z: number) {
    this.x = x;
    this.y = y;
    this.z = z;
  }

  toJson(): Object {
    return this;
  }

  static fromJson(obj: Object): Point3D {
    return new Point3D(obj['x'], obj['y'], obj['z']);
  }
}


class Foo {
  foo: Point2D;
  bar: Point3D;

  constructor(foo: Point2D, bar: Point3D) {
    this.foo = foo;
    this.bar = bar;
  }

  toJson(): Object {
    return {
      foo: this.foo.toJson(),
      bar: this.bar.toJson()
    }
  }

  static fromJson(obj: Object): Foo {
    return new Foo(Point2D.fromJson(obj['foo']), Point3D.fromJson(obj['bar']));
  }
}

var DATA: Object = {};

function getJsonData(): Object {
  return DATA;
}

function saveJsonData(o: Object) {
  DATA = o;
}

// Accepts types that are serializable
function save<T extends JsonSerializable>(o: T) {
  const json = o.toJson();
  saveJsonData(json);
}

// Accepts types that are deserializable
function loadData<InstanceType>(cls: JsonDeserializable<InstanceType>): InstanceType {
  const data = getJsonData();

  return cls.fromJson(data);
}

// Accepts types that are both serializable and deserializable
function testSerializationDeserialization<T extends JsonSerializable>(cls: JsonDeserializable<T>, obj: Object) {
  const instance = cls.fromJson(obj);
  const json = instance.toJson();

  assert.deepEqual(json, obj);
}

const foo = new Foo(new Point2D(1,2), new Point3D(1,2,3));

save(foo);
console.log(loadData(Foo)); // Foo object
testSerializationDeserialization(Foo, { foo: { x: 1, y: 2 }, bar: {x: 1, y: 2, z: 3}});

Answer №2

I suspect this could potentially address your inquiry. A class in JavaScript essentially functions as a sophisticated function, and a static element of a class is merely a property of that function (meaning it isn't part of the function's prototype).

Therefore, we have the ability to have T extend

Function & { new(...args: any): any } & { buildFormJson(input: object): InstanceType<T> }
. I've condensed the initial two segments of the intersection into a generic type known as ClassType<S> where S denotes the interface defining the static members.

function retrieveDataJson() {
    return {};
}

type ClassType<S> = Function & { new(...args: any): any } & S;

function retrieveData<T extends ClassType<{ buildFormJson(input: object): InstanceType<T> }>>(myClass: T) {
    return myClass.buildFormJson(retrieveDataJson());
}

class TestClass {
    static buildFormJson(): TestClass {
        return {};
    }
}

retrieveData(TestClass);

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

Error: TypeScript unable to locate file named "Image"

I'm encountering an issue while attempting to construct a class for loading images. The error message states that name "Image" not found within the array definition, even though I create an image object later in the code. class ImageLoad ...

Preventing window resize from affecting print screen content in Angular 8

I'm struggling with a print button feature in my Angular 8 project. When the window is resized, the content within the print window also resizes, which is not the behavior I want. I've tried a couple of solutions, but nothing has worked so far: 1 ...

Can you explain the functionality of the "lib" tsconfig option?

Hey, I'm currently working on a project and in the tsconfig.json file, there's this line: lib:["2016", "DOM"] Do you know what its purpose is? I did some research and came across this information: This setting specifies the library files to ...

Unable to fake a fetch request using the 'fetch-mock-jest 1.5.1' library

I am attempting to simulate a fetch call using thefetch-mock-jest library, but the code continues to try accessing the remote address and ultimately fails with the error message FetchError: request to https://some.domain.io/app-config.yaml failed, reason: ...

Obtain the hexadecimal color code based on the MUI palette color name

Is there a way to extract a hexcode or any color code from a palette color name in Material UI? Here is my use case: I have a customized Badge that I want to be able to modify just like the normal badges using the color property. The component code looks ...

Searching for particular information within an array of objects

Seeking guidance as a newbie on how to extract a specific object from an array. Here is an example of the Array I am dealing with: data { "orderid": 5, "orderdate": "testurl.com", "username": "chris", "email": "", "userinfo": [ ...

"React with Typescript - a powerful combination for

I'm facing an issue trying to create a simple list of items in my code. Adding the items manually works, but when I try to map through them it doesn't work. Apologies for any language mistakes. import './App.css' const App = () => { ...

Having trouble debugging a Typescript Vue app in VS Code?

When setting up my new Vue app, I followed these steps: ? Please pick a preset: Manually select features ? Check the features needed for your project: Choose Vue version, Babel, TS, PWA, Router, Vuex, CSS Pre-processors, Linter, Unit, E2E ? Choose a versio ...

Mastering the Implementation of Timetable.js in Angular with TypeScript

I am currently working on integrating an amazing JavaScript plugin called Timetable.js into my Angular6 project. You can find the plugin here and its repository on Github here. While searching for a way to implement this plugin, I stumbled upon a helpful ...

Creating a read-only DIV using Angular - a step-by-step guide

Is there a simple way to make all clickable elements inside a div read only? For example, in the provided HTML code, these divs act like buttons and I want to disable them from being clicked. Any tips or shortcuts to achieve this? Thank you. #html < ...

Can you specify the type of props that are typically passed in the setup function in Vue 3?

I have a question about using a render function inside a setup function. Specifically, I am curious about the type of props within the scope of setup. import { h, PropType } from 'vue' export default { props: { brand: { ty ...

`Is it possible to integrate npm libraries with typescript and ES6?`

I am looking to focus on using ES6 as the output for a node server-side app that I plan to run on the cutting-edge iojs distribution, which hopefully has support for the latest ES6 syntax. However, I'm unsure about how to integrate standard NPM libra ...

What makes `Why await` stand out from all the other broken promises?

I am puzzled by the behavior of promises in Node.js and I have a question about it. Let's take a look at the following function as an example: async function proc(): Promise<void> { const resolve = new Promise((resolve) => setTimeout(resolv ...

What is the functionality of react-table v7.7.9 when utilizing global filtering in a TypeScript environment?

My react-table component is functioning smoothly in typescript. const { getTableProps, getTableBodyProps, headerGroups, rows, prepareRow } = useTable( { columns, data } ); I am interested in implementing global filtering. When I incorporate the pl ...

Protractor Browser Instance Failure

We have encountered an issue with our UI suite failing in Chrome during the login process. Initially, we thought it might be due to upgrading to Chrome 79, as the problems arose simultaneously. Interestingly, the login functionality still works smoothly in ...

Clearing out all records from a Firestore collection

I attempted to implement the following method: deleteMessages(){ this.firestore.collection("MESSAGES") .get() .then(res => {res.forEach(element => {element.ref.delete();}); }); } However, I encountered the following err ...

Implementing TypeScript inheritance by exporting classes and modules

I've been struggling with TypeScript's inheritance, it seems unable to resolve the class I'm trying to inherit. lib/classes/Message.class.ts ///<reference path='./def/lib.d.ts'/> ///<reference path='./def/node.d.ts& ...

Please provide either a string or an object containing the proper key for TypeScript

Within my project, the languageSchema variable can either be a string or an object containing the 'Etc' key. The corresponding interface is defined as follows: let getLanguageSchema = (language: string): string => languagesSchemas[language]; ...

Selenium Intern issue: ERROR - suiteEnd message received for session that does not exist

I have been attempting to set up functional testing using Intern 4 with a headless Chrome browser. I have installed selenium-server-standalone on my Mac terminal and believe everything is configured correctly. However, when I try to run the test, I encount ...

Guide on transforming a tuple of random types into a nested type structure with the help of recursive conditional types

When I responded to the query on whether Typescript Interfaces can express co-occurrence constraints for properties, I shared the following code snippet: type None<T> = {[K in keyof T]?: never} type EitherOrBoth<T1, T2> = T1 & None<T2&g ...