TypeScript: additional information on the properties of an interface

Attempting to develop a framework that enables meta on interface fields. Consider the following example:

function path(path) {}

interface ITwoProps {
  @path('some/path') stringProp: string;
  @path('different/path') boolProp: boolean;
}

class Impl1 implements ITwoProps {
  get stringProp() {
    return 'abc';
  }
  get boolProp() {
    return !!'abc';
  }
}

playground link

Unfortunately, this code does not compile due to decorators being disabled on interfaces for non-transpiled code attachment reasons.

Alternative approaches have been considered, such as defining meta and interfaces with schema-like objects:

const Schema = {
  boolProp: {
    type: Boolean,
    path: 'some/path'
  },
  stringProp: {
    type: String,
    path: 'different/path'
  },
};

type PropertyDef<T> = {
  type: (...args: any[]) => T,
  path?: string;
};

type ExtractType<X> = X extends PropertyDef<infer T> ? T : never;

type ObjectInterface<T extends {[key: string]: PropertyDef}> = {
  [P in keyof T]: ExtractType<T[P]>;
}

class Impl2 implements ObjectInterface<typeof Schema> {
  get foo() {
    return !!'abc';
  }
}

playground link

Issues arise with this approach as well, particularly with PropertyDef requiring a parameter.

The main question remains - how can an interface be combined with meta in TypeScript? Open to suggestions, even those involving transformers using the Compiler API.

Answer â„–1

The utilization of decorators within interfaces lacks language support, and according to @Daniel-Rosenwasser, it is unlikely to receive such support in the future. One workaround could involve utilizing abstract classes and employing implements with classes to maintain the interface structure while excluding the actual code, although this method may lead to confusion.

However, revisiting the second approach might prove beneficial. With just an additional <any>, the functionality can be enhanced. This approach offers more flexibility as it provides complete control over the metadata system. I have experimented with crafting intricate types using a similar system and achieved success. In your scenario, the following implementation would suffice:

const Schema = {
  boolProp: {
    type: Boolean,
    path: 'some/path'
  },
  stringProp: {
    type: String,
    path: 'different/path'
  },
};

type PropertyDef<T> = {
  type: (...args: any[]) => T,
  path?: string;
};

type ExtractType<X> = X extends PropertyDef<infer T> ? T : never;

type ObjectInterface<T extends { [key: string]: PropertyDef<any> }> = {
  [P in keyof T]: ExtractType<T[P]>;
}

class Impl2 implements ObjectInterface<typeof Schema> {
  get boolProp() {
    return !!'abc';
  }
  get stringProp() {
    return '';
  }
}

Answer â„–2

When it comes to decorators, they operate with runtime emit and receive information tied to the declarations they are enhancing. In contrast, interfaces lack any runtime emit capability, leaving decorators with no data to work with other than the name.

The crux of the problem lies in TypeScript's restriction on placing decorators on interface members, as it would be nonsensical without the support of a build tool.

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

Add a Filter to the Observer (__ob__) in Typescript

I am trying to implement a filter using this.Grid.option("dataSource").filter(x => x.Placeholder != null) however, it doesn't seem to be working when I run console.log(this.Grid.option("dataSource")); I receive (72) [{…}, {…}, {…}, {†...

Angular 5 is encountering an error with a recursive template, specifically a RangeError stating that the maximum call stack

Hey there, I'm currently utilizing Angular recursive template to represent arrays recursively. The code I've been following is provided in this link. My array is dynamic in nature. <ul> <ng-template #recursiveList let-list> ...

Mongodb Dynamic Variable Matching

I am facing an issue with passing a dynamic BSON variable to match in MongoDB. Here is my attempted solutions: var query = "\"info.name\": \"ABC\""; and var query = { info: { name: "ABC" } } However, neither of thes ...

Error in Angular 7: Trying to assign a 'void' type to a 'ObservableInput<{}>' type

I can't seem to understand why I am encountering this error fetchFromURL(url: string): any { return this.apiService.get(url).pipe(map(data => data)); } fetchNextPage(): Observable<any> { const url = 'url'; this.f ...

Querying the api for data using Angular when paginating the table

Currently, I have a table that retrieves data from an API URL, and the data is paginated by default on the server. My goal is to fetch new data when clicking on pages 2, 3, etc., returning the corresponding page's data from the server. I am using an ...

Utilizing Typescript's baseUrl compiler configuration for node development

Is there a way for node's module loader to support TS's baseUrl compiler option? With the introduction of the baseUrl compiler option in TS 2, project relative require() and import requests are now possible. However, this feature requires that ...

Compiled TypeScript files are missing require statements for imported components

Recently delved into Angular 2 and encountered an unusual issue. I kicked off using the Angular 2 Quickstart repository on GitHub and incorporated some components with templates. For example: import { Component } from '@angular/core'; import { ...

Typescript throws an error when attempting to return an array of strings or undefined from a function

I created a shallow differences function that compares two arrays of strings and returns either undefined (if the arrays are different lengths) or a string array containing matching characters at corresponding indexes. If the characters don't match, i ...

tsconfig.json configuration file for a project containing both `src` and `tests` directories

Looking to achieve a specific project structure: - tsconfig.json - src - app.ts - tests - appTest.ts - appTest.js - dist - app.js If the tests folder did not exist, this tsconfig.json configuration would suffice: { "compilerOptions": ...

Issue encountered on server using next.js - FetchError: failed to process request for https://jsonkeeper.com/b/4G1G

Struggling to fetch JSON data from a link and destructure it for use on the website. I have a getStaticProps export function that extracts the data and I want to pass it into my default Home function to iterate through it. I have come across information ab ...

The unit tests are not triggering the execution of setTimeout

Currently, I am developing a project in TypeScript and for unit-tests, I am utilizing QUnit and sinonjs. One of the functions within my code dynamically renders UI elements. I need to retrieve the width of these dynamic elements in order to perform additio ...

Vitek - Uncaught ReferenceError: Document Is Not Defined

Why am I encountering an error when trying to use File in my vitest code, even though I can typically use it anywhere else? How can I fix this issue? This is the content of my vite.config.ts. /// <reference types="vitest" /> import { defin ...

Retrieve contextual information within standard providers

I'm currently using nestjs to create a straightforward HTTP rest API, utilizing typeorm. I have set up 2 Postgres databases and would like the ability to access both, although not necessarily simultaneously. Essentially, I am looking to designate whi ...

Having trouble injecting $resource into my Jasmine unit test

I've encountered an issue while trying to test my self-written service that utilizes $resource. I'm facing difficulties when trying to inject $resource into my test spec. My setup includes Typescript with AngularJS 1.6.x, and here is a snippet o ...

Issue with customizing border color in Mui text field

Why is the border color of the Mui textField not remaining black when the user enters or selects data for the input fields? It still shows blue as in the photo. Here is the code: enter image description here.Here is the code. I'm wondering why this i ...

What is the best way to effectively utilize Material UI breakpoints in combination with styled components?

Here is my code: const FooterBox = styled(Box)` background: #4e738a; left: 0; right: 0; bottom: 0; width: 100%; color: #ffffff; ${p => p?.theme?.breakpoints.up('xs')} { margin: auto; display: flex; flex-direction ...

What steps can be taken to transform a React Functional Component utilizing hooks into a class-based component?

Encountering roadblocks while attempting to convert a React Functional Component to a class. Below is the functional component code: import * as React from 'react'; import { withStyles } from '@material-ui/core/styles'; import Drawer ...

Greetings, Angular2 application with TypeScript that showcases the beauty of the world

I've been working on my first angular2 program and noticed some deviations from the expected output. typings.json: { "ambientDependencies": { "es6-shim": "github:DefinitelyTyped/DefinitelyTyped/es6-shim/es6-shim.d.ts#7de6c3dd94feaeb21f20054b9f ...

Exploring the Enum Type in GraphQL Apollo Query

Within the server environment, I have defined the enum and query in the schema: type Query { hello: String! getData(dataType: DataType!): [DataPoint] } enum DataType { ACCOUNT, USER, COMPANY } ... Now, on the client s ...

What is the best way to retrieve the value of an input field in React when incorporating Material UI components?

I am working with a few radio input components that have been imported from material Ui react. Each radio input is wrapped in a FormControlLabel component. <FormControlLabel onClick={checkAnswerHandler} value={answer} control={<Radio color=&quo ...