0

Is it possible to extend an interface and override a member's type as in the example below? I would like to be able to do this so that when I create an object of type IPathParam the compiler knows that the required property should be true and not omitted or false. With the code below, the compiler complains that type 'path' is not assignable to type 'header' | 'query'

interface IParam {
  in: 'header' | 'query'
  required?: boolean
  ...
}

interface IPathParam extends IParam {
  in: 'path'
  required: true
}
Ben Guest
  • 1,488
  • 2
  • 17
  • 29
  • Possible duplicate of [Overriding interface property type defined in Typescript d.ts file](https://stackoverflow.com/questions/41285211/overriding-interface-property-type-defined-in-typescript-d-ts-file) – Murat Karagöz Apr 21 '19 at 12:57
  • 2
    Let's say you live in a country where the law says "all jobs must be paid using an amount specified in the contract, in dollars". Would you like it if a state of this country was allowed to still respect the law by overriding the law and replacing the type "dollars" with "peanuts"? An interface is a contract. All extensions and implementations of the interface must obey to this contract. The interface says: "every object of type IParam will have a property `in` of type 'header' | 'query'". Overriding the type to 'path' would violate the contract. – JB Nizet Apr 21 '19 at 13:07
  • @JBNizet Okay sure, that makes sense. I probably need to refactor the `IParam` interface then into an `IHeaderParam` and `IQueryParam` interface, each of which define their specific value for `in` so that it can still be used as the discriminator property – Ben Guest Apr 21 '19 at 13:49

1 Answers1

1

You can't do this, and for good reason as pointed out in the comments. The idea of subtypes is that an instance of the subtype is still an instance of the base type. Changing a member type would violate this constraint.

Now if you just want a type that is mostly the same as the interface but has one member that is different, we can do this using Omit and intersections. Note that this new type will not be a subtype of your interface, but it might still prove useful in some cases:

type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>

interface IParam {
    in: 'header' | 'query'
    required?: boolean

}

type ISimilarToParam = Omit<IParam, 'in'> & {
    in: 'path'
};
Titian Cernicova-Dragomir
  • 230,986
  • 31
  • 415
  • 357