question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. ItĀ collects links to all the places you might be looking at while hunting down a tough bug.

And, if youā€™re still stuck at the end, weā€™re happy to hop on a call to see how we can help out.

`override` modifier should able to be used with `declare` modifier

See original GitHub issue

Suggestion

šŸ” Search Terms

useDefineForClassFields override declare ā€˜overrideā€™ modifier cannot be used with ā€˜declareā€™ modifier. ts(1243) Property ā€˜aā€™ will overwrite the base property in ā€˜Clsā€™. If this is intentional, add an initializer. Otherwise, add a ā€˜declareā€™ modifier or remove the redundant declaration.(2612)

āœ… Viability Checklist

My suggestion meets these guidelines:

  • This wouldnā€™t be a breaking change in existing TypeScript/JavaScript code
  • This wouldnā€™t change the runtime behavior of existing JavaScript code
  • This could be implemented without emitting different JS based on the types of the expressions
  • This isnā€™t a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, new syntax sugar for JS, etc.)
  • This feature would agree with the rest of TypeScriptā€™s Design Goals.

ā­ Suggestion

When declaring class fields:

The override modifier should be able to be used with declare modifier.

Have ! work in the place of declare OR: Remove this error if ! or override is specifically given: Property ā€˜aā€™ will overwrite the base property in ā€˜Clsā€™. If this is intentional, add an initializer. Otherwise, add a ā€˜declareā€™ modifier or remove the redundant declaration.(2612)

šŸ“ƒ Motivating Example

Given a decorator Prop() that somehow declares some metadata on the class field, that would later be used in some other technical components like Database ORMs or Validators, etc.

Consider this example, before useDefineForClassFields set to true:

interface Animal {
  animalStuff: any;
}
interface Dog extends Animal {
  dogStuff: any;
}

class AnimalHouse {
  internalProp: number;

  @Prop({
    default: {
      animalStuff: 'food',
    }
  })
  resident: Animal;

  @Prop({
    default: 'foo'
  })
  someOtherProp: string;

  constructor(animal: Animal) {
    this.resident = animal;
  }
}

class DogHouse extends AnimalHouse {
  @Prop({
    default: {
      animalStuff: 'food',
      dogStuff: 'dog food',
    }
  })
  override resident: Dog;
}

Note that the DogHouse is defined quite straightforward and expected in a general sense.

Now after useDefineForClassFields set to true, the current way of specifying the DogHouse becomes:

class DogHouse extends AnimalHouse {
  @Prop({
    default: {
      animalStuff: 'food',
      dogStuff: 'dog food',
    }
  })
  declare resident: Dog;
}

It doesnā€™t look too bad, but things can get more complicated:

class DogHouse extends AnimalHouse {
  override internalProp: 42;

  @Prop({
    default: {
      animalStuff: 'food',
      dogStuff: 'dog food',
    }
  })
  declare resident: Dog;
  
  @Prop({
    default: 'foo'
  })
  override someOtherProp: string = 'foo';
  
  @Prop({
    default: 'foo'
  })
  someOtherProp2: string;
}

Now it sucks.

The consistency and readability from using override is completely screwed up by declare.

At least the override should be allowed to be used with declare to make it suck a little less:

class DogHouse extends AnimalHouse {
  override internalProp: 42;

  @Prop({
    default: {
      animalStuff: 'food',
      dogStuff: 'dog food',
    }
  })
  declare override resident: Dog;

  @Prop({
    default: 'foo'
  })
  override someOtherProp: string = 'foo';
  
  @Prop({
    default: 'foo'
  })
  someOtherProp2: string;
}

The best case however, is to have ! work in the place of declare:

class DogHouse extends AnimalHouse {
  override internalProp: 42;

  @Prop({
    default: {
      animalStuff: 'food',
      dogStuff: 'dog food',
    }
  })
  override resident!: Dog; // No declaration emit
  
  @Prop({
    default: 'bar'
  })
  override someOtherProp: string; // With declaration emit
  
  @Prop({
    default: 'foo'
  })
  someOtherProp2: string;
}

šŸ’» Use Cases

As example suggested.

The code readability degradation from declare is unacceptable.

I am using typescript with useDefineForClassFields set to off now.

Please consider my suggestionā€¦

Issue Analytics

  • State:open
  • Created 10 months ago
  • Comments:8

github_iconTop GitHub Comments

1reaction
nomagickcommented, Nov 15, 2022

Iā€™ve put it in another way, hopefully it can convenience you more. https://github.com/microsoft/TypeScript/issues/51536

1reaction
nomagickcommented, Nov 15, 2022

@fatcerberus Apologies If my words are too offensive. Iā€™m not very good at English after all. I just wanted to express my feeling on this issue and the direction it is developing. Now I believe you have acknowledged my frustration. I hope the user frustration still means something to TS devs. Maybe Iā€™ll start a new issue and rephrase all about this after further discussion.

Itā€™s not about the new ES Class define behaviour, not on their part. This is exactly a TypeScript issue.

According to your own reply here, you are well aware of no matter what TS do, the eventual behaviour will change because of the underlying runtime. Then itā€™s ok to treat it transparently and not throw errors on this:

class DogHouse extends AnimalHouse {
  @Prop({
    default: {
      animalStuff: 'food',
      dogStuff: 'dog food',
    }
  })
  override resident!: Dog;
}

At least it should have an option to disable this error. Property 'resident' will overwrite the base property in 'AnimalHouse'. If this is intentional, add an initializer. Otherwise, add a 'declare' modifier or remove the redundant declaration.(2612)

FYI the decorator is working as expected. I authored those decorators. Itā€™s using the metadata registering approach. Itā€™s not about the code not working; it works. Itā€™s about TypeScript not allowing this formerly-valid clear, precise way of writing code anymore, and proposes another much less favourable approach, known as declare.

Read more comments on GitHub >

github_iconTop Results From Across the Web

override modifier - C# Reference | Microsoft Learn
An overriding property declaration must specify exactly the same access modifier, type, and name as the inherited property.
Read more >
Method Overriding with Access Modifier - GeeksforGeeks
While doing method overriding in SubClass Class B we didn't define any access modifier so Default access modifier will be used.
Read more >
curious case of putting override modifier when ... - eed3si9n
Scala requires [ override ] modifier for all members that override a concrete member in a parent class. The modifier is optional if...
Read more >
Override modifier is not allowed in Main however it is allowed ...
I am trying to create a Launcher program for my application and was going through the App trait and main method to decide...
Read more >
modifier_order Reference - Realm Open Source
Modifier order should be consistent. Identifier: modifier_order; Enabled by default: No; Supports autocorrection: Yes; Kind: style; Analyzer rule: NoĀ ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found