Closed
Description
This is a proposal for solving the second use case mentioned in Issue #6218
Problem
/**
* This class is a given by the React framework
*/
class ReactComponent<S> {
protected _state: S;
/**
* This method actually accepts any supertype of S
*/
protected setState(newState: S): void {
for (let name in newState) {
if (newState.hasOwnProperty(name)) {
this._state[name] = newState[name];
}
}
}
protected componentWillMount(): void {
// abstract
}
}
/**
* Some state interface declaration. Note all members are optional to allow setState to
* be called with supertypes of BaseState
*/
interface BaseState {
a?: string;
}
/**
* My own base class for certain React widgets
*/
class BaseWidget<S extends BaseState> extends ReactComponent<S> {
constructor() {
super();
this._state = {};
}
protected componentWillMount(): void {
this.setState({ a: "boo" });
}
}
$ tsc v1.ts
v1.ts(39,9): error TS2322: Type '{}' is not assignable to type 'S'.
v1.ts(43,23): error TS2345: Argument of type '{ a: string; }' is not assignable to parameter of type 'S'.
The compiler cannot know that the setState() method will accept any super-type of S, i.e. an object with any subset of the members of S.
Proposal
Add a keyword to type setState() properly. To avoid confusion, I chose partof instead of e.g. 'supertype of' (see also initial confusion in #6218). For me, 'partof' conveys that I can give the method any object with a subset of the members of S.
/**
* This class is a given by the React framework
*/
class ReactComponent<S extends {}> {
protected _state: S;
/**
* This method accepts any supertype of S
*/
protected setState(newState: partof S): void {
}
}
Properties of partof
- Only works for object types (hence the 'extends {}' above) because I wouldn't know how to pass part of e.g. a string
- Allows any supertype of the given type
- Incorporates knowledge of the generic parameter. Given the class declaration
class ReactComponent<S extends { foo: number; }>
, one is able to callsetState({ foo: 3})
andsetState({})
but notsetState({ bar: 3 })
inside the class definition.
Comments more than welcome, I'm not a compiler expert. This is just to get the discussion going. If you think there already exists a way of typing this, please check with the original issue for a couple of failed examples.