-
Notifications
You must be signed in to change notification settings - Fork 12.9k
Closed
Labels
By DesignDeprecated - use "Working as Intended" or "Design Limitation" insteadDeprecated - use "Working as Intended" or "Design Limitation" insteadDeclinedThe issue was declined as something which matches the TypeScript visionThe issue was declined as something which matches the TypeScript visionSuggestionAn idea for TypeScriptAn idea for TypeScript
Description
It seems like the rules for a) implementing multiple interfaces and b) intersection types should be consistent.
Example 1: Optional members
interface A { m1: string;}
interface B { m1?: string;}
// allowed, m1 is required.
type CT = A&B;
var a : CT = {m1:undefined};// allowed, string can be undefined
// error, m1 is required,
//TS2322: Type '{}' is not assignable to type 'A & B', Property 'm1' is missing in type '{}'.
var b : CT = {};
// not allowed, TS2320, Named property 'm1' of types 'A' and 'B' are not identical.
interface C extends A, B {}
Example 2: Protected members
class P { protected m1: number; }
class Q { m1: number; }
// allowed, m1 is public
type PQT = P&Q;
var p : PQT = <PQT>{m1:undefined};
p.m1; // allowed, m1 is public in PQT
// not allowed
// TS2420: Class 'PQ' incorrectly implements interface 'Q'
// Property 'm1' is protected in type 'PQ' but public in type 'Q'.
class PQ extends P implements Q {}
// TS2420: Class 'QP' incorrectly implements interface 'P'.
// Property 'm1' is protected but type 'Q' is not a class derived from 'P'.
class QP extends Q implements P {}
// Allowed to relax protection explicitly in a derived class
class PQX extends P implements Q { m1: number;}
// Not allowed - again, seems a bug.
class QPX extends Q implements P { m1: number;}
// Workaround is to use an intermediate class to relax the protection
class PX extends P {m1: number;}
class QPX2 extends Q implements PX { m1: number;}
- Implementing multiple interfaces should create a type which is the intersection of the types of the interfaces (but with any new members added).
- It should not be an error to make an optional member non-optional in a derived class. Non-optional members can be undefined, so nothing should break. This is consistent with intersection types. (Arguably also vice versa.)
- It should not be an error to relax the protected or private status of a member in a derived or implementing class, consistent with intersection types. (in 1.6 you can do it in a derived class but not an implementing class). Or at any rate it should be possible to do so if you need to. See also Allow interfaces to declare protected members and allow implementors to implement protected and private members. #3854
(Surely from a strict point of view Q above is a subtype of P, because it can be used wherever P is used. All members visible externally on P are visible externally on Q, and all members visible internally on P are visible internally on Q. So I think that makes Q a subtype of P.)
Implementing two or more interfaces should create the same type as the intersection of the types. That they don't seems like a bug.
In pseudocode, this:
interface C extends A, B {}
Should be identical in effect to this (if it was a thing):
type C1 = A & B;
interface C extends C1 {}
Metadata
Metadata
Assignees
Labels
By DesignDeprecated - use "Working as Intended" or "Design Limitation" insteadDeprecated - use "Working as Intended" or "Design Limitation" insteadDeclinedThe issue was declined as something which matches the TypeScript visionThe issue was declined as something which matches the TypeScript visionSuggestionAn idea for TypeScriptAn idea for TypeScript