Allow deriving from object and intersection types#13604
Conversation
|
|
||
| // A valid base type is any non-generic object type or intersection of non-generic | ||
| // object types. | ||
| function isValidBaseType(type: Type): boolean { |
There was a problem hiding this comment.
Return type could be : type is BaseType ?
There was a problem hiding this comment.
Well, BaseType is the most restrictive type we can express for a valid base type, but there are still BaseType instances that aren't valid base types (e.g. intersections containing type parameters). So, wouldn't be correct in the negative sense.
|
In the second block of examples, are N1 and N2 missing |
|
@jwbay Yes, thanks. Now fixed. |
mhegazy
left a comment
There was a problem hiding this comment.
Please add some tests for the changes in the apparent type for this in intersection types.
|
I'm not 100% sure but it seems like this change breaks a common pattern I use (and probably others, at least in the future) with React. This worked in yesterday's nightly build: export class MyComponent extends React.Component<{ someValue: number }, {}> {
shouldComponentUpdate(nextProps: this["props"], nextState: this["state"]) {
if (nextProps.someValue > 0) {
// ...
}
}
}But now errors: The problem might be related to the fact that {
children?: React.ReactNode;
} & {
someValue: number;
}I've tried to work around this by using export class MyComponent extends React.Component<{ someValue: number }, {}> {
shouldComponentUpdate(nextProps: typeof this.props, nextState: typeof this.state) {
if (nextProps.someValue > 0) {
// ...
}
}
}
// Error on 'typeof this.props': Identifier expectedThe relevant ambient declaration for // Base component for plain JS classes
class Component<P, S> implements ComponentLifecycle<P, S> {
constructor(props?: P, context?: any);
constructor(...args: any[]);
// ...
props: { |
With this PR we permit classes and interfaces to derive from object types and intersections of object types. Furthermore, in intersections of object types we now instantiate the
thistype using the intersection itself. Collectively these changes enable several interesting "mixin" patterns.In the following, a type is said to be object-like if it is a named type that denotes an object type or an intersection of object types. Object-like types include named object literal types, function types, constructor types, array types, tuple types, mapped types, and intersections of any of those.
Interfaces and classes may now extend and implement types as follows:
extendany object-like type.extendan expression of a constructor type with one or more construct signatures that return an object-like type.implementsany object-like type.Some examples:
An interface or class cannot extend a naked type parameter because it is not possible to consistently verify there are no member name conflicts in instantiations of the type. However, an interface or class can now extend an instantiation of a generic type alias, and such a type alias can intersect naked type parameters. For example:
The
thistype of an intersection is now the intersection itself:All of the above can be combined in lightweight mixin patterns like the following:
Also, mixin classes can be modeled, provided the base classes have constructors with a uniform shape:
We're still contemplating type system extensions that would allow the last example to be written without type assertions and in a manner that would work for arbitrary constructor types. For example, see #4890.
EDIT: Mixin classes are now implemented by #13743.
Fixes #10591.
Fixes #12986.