Skip to content

override modifier should able to be used with declare modifier #51515

Open
@nomagick

Description

@nomagick

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..

Metadata

Metadata

Assignees

No one assigned

    Labels

    In DiscussionNot yet reached consensusSuggestionAn idea for TypeScript

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions