Skip to content

How to override return types of methods from children - JSII5003 #3068

Closed
@KyleTryon

Description

@KyleTryon

❓ Guidance

While I am submitting this for guidance, this is a blocking issue me. Errors point out this is a limitation issue, but not how to resolve it. See below for details.

Affected Languages

  • TypeScript or Javascript
  • Python
  • Java
  • .NET (C#, F#, ...)
  • Go

General Information

  • JSII Version: 1.34.0 (build 9b72778), typescript 3.9.10
  • Platform:. 18.7.0 Darwin Kernel Version 18.7.0

The Question

Below is a simplified example of a common pattern in TypeScript using abstract classes (could easily interface instead, it should not matter for this) to group elements of a similar type. In this case, we have the Vehicle abstract class, and it states that all vehicles should contain a properties property. As Vehicle is the most generic structure for vehicles, the type is set to unknown.

Then we define two child classes which extendVehicle. Both Car and Plane will have properties, but we expect their type to be different. We do this so we can call properties on any vehicle, and so when users are instantiating either a Car or Plane, they receive the correct code-hints.

// The most generic, abstract class "vehicle"
// This class joins our "vehicles" under a shared type

export abstract class Vehicle {
  properties: unknown;
}

export class Car extends Vehicle {
  properties: CarProperties;
  constructor(properties: CarProperties) {
    super()
    this.properties = properties
  }
}

export class Plane extends Vehicle {
  properties: PlaneProperties;
  constructor(properties: PlaneProperties) {
    super()
    this.properties = properties
  }
}

interface CarProperties {
  doors: number;
  color: string;
}

interface PlaneProperties {
  wings: number;
  callSign: string;
}

The code above is valid and working TypeScript, but this will not compile under JSII due to JSII5003

// This pattern above exists so that we might
// do something like the following:
const myVehicles: Vehicle[] = []
const myCar = new Car({doors: 2, color: "red"}) // proper type code-hints are given here
const myPlane = new Plane({wings: 2, callSign: "bravo"}) // proper type code-hints are given here

myVehicles.push(myCar)
myVehicles.push(myPlane)

myVehicles.forEach( vehicle => {console.log(vehicle.properties.toString())})

Error:

Type model errors prevented the JSII assembly from being created
error JSII5004: "Car#properties" changes the property type to "CarProperties" when overriding Vehicle. Change it to "unknown"

The only way around this I see is to drop the Typing on Car and Plane, which would leave the user blind when instantiating those classes. What is the recommended pattern for dealing with this type of scenario with JSII?

Edit:

I have just discovered #2314 which appears to be the same topic

Metadata

Metadata

Assignees

No one assigned

    Labels

    guidanceQuestion that needs advice or information.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions