What are the real-world applications of "Type-only Field Declarations"?

Source: Type-only Field Declarations.

interface Animal {
  dateOfBirth: any;
}
 
interface Dog extends Animal {
  breed: any;
}
 
class AnimalHouse {
  resident: Animal;
  constructor(animal: Animal) {
    this.resident = animal;
  }
}
 
class DogHouse extends AnimalHouse {
  // This code snippet does not generate JavaScript code,
  // it simply ensures that the types are correctly defined    
  declare resident: Dog;
  constructor(dog: Dog) {
    super(dog);
  }
}

While I understand the official example, I'm curious about practical applications of this concept. Are there any real-world examples of where this type-only field declaration should be used?

Answer №1

To prevent the emission of a public class field to JavaScript, it is recommended to use the declare modifier on the class field. TypeScript's implementation of class field declarations differed from JavaScript's, where an uninitialized field defaults to undefined. To inherit a property but narrow its type in a subclass, the declare modifier should be used.


For instance, consider a base Tree class with a property value of type the unknown type and an array children containing Tree elements:

// TypeScript input
class Tree {
    value: unknown;
    children: Tree[] = [];
    constructor(value: unknown) {
        this.value = value;
    }
}

Depending on the target and TS config settings, the emitted output may remove only the types:

// JavaScript output
class Tree {
    value;
    children = [];
    constructor(value) {
        this.value = value;
    }
}

Now, creating a StringTree subclass where value is restricted to string and children is an array of StringTree elements was best achieved by re-declaring fields in TypeScript:

// TypeScript input
class StringTree extends Tree {
    value!: string; 
    children!: StringTree[];
    constructor(value: string) {
        super(value);
    }
}

However, this approach may not yield the desired output:

const b = new StringTree("hello");
console.log(b.value.toUpperCase()) // RUNTIME ERROR, b.value is undefined

The subclass properties are initialized to undefined after super() call, leading to errors. In such cases, the error can be addressed using the declare modifier instead:

// TypeScript input
class StringTree extends Tree {
    declare value: string;
    declare children: StringTree[];
    constructor(value: string) {
        super(value);
    }
}

Subsequent output will work as intended:

// JavaScript output
class StringTree extends Tree {
    constructor(value) {
        super(value);
    }
}

Resulting in the desired behavior:

const a = new StringTree("hello");
console.log(a.value.toUpperCase()) // "HELLO"

Playground link to code

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 type 'Argument of (props: ITableProps) => JSX.Element' cannot be assigned to the parameter type of... - React High Order Component

One of the tools I have in my arsenal is a loader HOC This is how the HOC looks like: const withLoader = <P extends object>(WrappedComponent: new () => React.Component<P, any>, loading: boolean) => { return class WithLoading extends ...

Utilize fixed values in type declaration

Strange Behavior of Typescript: export type MyType = 0 | 1 | 2; The above code snippet functions correctly. However, the following code snippet encounters an issue: export const ONE = 1; export const TWO = 2; export const THREE = 3; export type MyType = O ...

Discovering the category for ethereum, provider, and contract

My current interface looks like this: interface IWeb3 { ethereum?: MetaMaskInpageProvider; provider?: any; contract?: any; }; I was able to locate the type for ethereum using import { MetaMaskInpageProvider } from "@metamask/providers", ...

Exploring the process of inferring union types in TypeScript

const type p1 = { a: number, b: string } const type p3 = { a: string } const type p4 = p1 | p3 let sample: p4 = { a: '123', b: '123' } function checkP3(obj: p4): obj is p3 { return typeof (<p3>obj).a === 'string' ...

Is it possible to dynamically check values in TypeScript?

[Summary] I am looking to dynamically expand my type in TypeScript based on an initial set of values. I want to avoid managing separate arrays/types and instead extend all strings in my type with '_max'. type ExtendedValueTypes = 'money&apos ...

Include the designated return type within a fat arrow function

No matter how hard I look, I cannot figure out the correct way to combine return type annotation with fat arrow syntax. class BasicCalculator{ value:number; constructor(value:number=0){ this.value=value; } add= (operand:number)=> ...

Expanding ngFor in Angular 2

Is it possible to pass two arguments with ngFor? Here is an example that I would like to achieve: <mat-card *ngFor="let room of arr; let floor of floorArr"> <mat-card-content> <h3>Room Number: {{room}}</h3> <p>Floor ...

Set panning value back to default in Ionic

I need assistance with resetting the panning value. Essentially, I would like the panning value to return to 0 when it reaches -130. Below is my code snippet: swipeEvent($e) { if ($e.deltaX <= -130) { document.getElementById("button").click(); ...

Is it possible for changes made to an object in a child component to be reflected in the parent component

When passing an object to the child component using , how can we ensure that changes made to a specific property in the object within the child component are visible in the parent component? In my understanding, changes would not be reflected if we were p ...

Do I have to create all the classes returned when consuming a JSON web service in Angular/Typescript?

I would like to access this service: https://maps.googleapis.com/maps/api/geocode/json?address=1600+Amphitheatre+Parkway,+Mountain+View,+CA&key=YOUR_API_KEY I am interested in extracting only two pieces of data: "location" : { " ...

Angular 6: A guide to dynamically highlighting navbar elements based on scroll position

I am currently building a single page using Angular 6. The page is quite basic, and my goal is to emphasize the navbar based on scrolling. Below is the code snippet I am working with: .sticky { position: sticky; top: 0; } #i ul { list-style-type: ...

Generate a table in MongoDB using NestJs without the need to create a new collection

I am facing a challenge with my app where I need to create an order with multiple attributes, one of which is an array of ordered products. Each object in the orderedProduct array must include the productId and the amount. However, I do not want to create ...

Discovering the proper method for indicating the type of a variable in the middle of a statement

In my code, there was a line that looked like this: let initialPayload = this.db.list("/members").snapshotChanges() as Observable<any[]> But then I changed it to this: let initialPayload = this.db.list("/members").snapshotChanges ...

I am able to view the node-express server response, but unfortunately I am unable to effectively utilize it within my Angular2 promise

https://i.stack.imgur.com/d3Kqu.jpghttps://i.stack.imgur.com/XMtPr.jpgAfter receiving the object from the server response, I can view it in the network tab of Google Chrome Dev Tools. module.exports = (req, res) => { var obj = { name: "Thabo", ...

The statement 'typeof import("...")' fails to meet the requirement of 'IEntry' constraint

When trying to run npm run build for my NextJS 13 app, I encountered the following type error: Type error: Type 'typeof import("E:/myapp/app/login/page")' does not satisfy the constraint 'IEntry'. Types of property 'def ...

Retrieve a multitude of nested Records within the returnType that correlate with the number of arguments provided to the function

My goal is to dynamically define a deeply nested ReturnType for a function based on the number of arguments passed in the "rest" parameter. For example, if we have: getFormattedDates( dates: Date[], ...rest: string[] // ['AAA', 'BBB&apos ...

Array of colors for Wordcloud in Angular Highcharts

I am currently utilizing Angular Highcharts 9.1.0 and facing an issue with generating a word cloud that incorporates specific colors. Despite including color values in the array, they do not seem to be applied as intended. Take a look at the code snippet b ...

Experience the dynamic synergy of React and typescript combined, harnessing

I am currently utilizing ReactJS with TypeScript. I have been attempting to incorporate a CDN script inside one of my components. Both index.html and .tsx component // .tsx file const handleScript = () => { // There seems to be an issue as the pr ...

The name is not found when using attribute, but it is found when using extends

Lately, I've encountered difficulties with creating large TypeScript modules, and there's one thing that has been puzzling me. Specifically, the following scenario doesn't seem to work: // file A.ts export = class A { } // file main.ts imp ...

My goal is to develop a secure login system with authentication on the Angular platform

login(data: any) { this.user.getUsers().subscribe( (users) => { const user = users.find((u) => u.username === data.username && u.userpassword === data.password); if (user) { // Valid username and password, ...