-
Notifications
You must be signed in to change notification settings - Fork 12.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Sub-type type #6218
Comments
I think you mean a supertype, not a subtype. In TypeScript 1.8, you'll be able to write interface Options {
a: string;
b: string;
}
const defaults: Options = {
a: "a",
b: "b"
}
function merge<T extends U, U>(base: T, additional: U): T {
return base;
}
let opts = merge(defaults, { b: "some other b" }) Try it out by running Does this address your use cases? |
Hi @DanielRosenwasser thanks for your reply. It definitely addresses the first use case but not the second. This is because it is not possible to explicitly mention the supertype (and you were of course right about it being a supertype) and therefore you cannot make a proper signature for the setState method. Using |
@rogierschouten What about this? (didn't try)
|
@rogierschouten what if you just made all the properties optional? I think that's the usual approach. |
@lbguilherme do you mean this? It generates the compile errors below. /**
* 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<S extends T>(newState: T): 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" });
}
}
|
@DanielRosenwasser your solution only works when you don't have an intermediary base class: /**
* 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" });
}
}
This is because the compiler cannot know that the S that the BaseWidget is instantiated with doesn't have any additional required members. It is for this reason we need the supertype designation in the setState parameter so the compiler knows that this doesn't matter. |
@rogierschouten Specifying a
But... this is too unrestricted. When S is |
@lbguilherme Yes I agree, there should be another language construct. Can somebody maybe remove the Question label from this issue and put something in that reflects this? |
At this point I'd prefer we have a new issue putting forth a concrete proposal (hopefully specifically addressing typing of |
same issue here. If you use React + Typescript and you have some React components extending other components and you try to properly define the states with interfaces (with all properties being optional) it leads exactly to the problem described in usecase 2 above. In other words, even though you provide a proper state object
Sadly the only solution that I could find to make it work for now is to turn off the typecheck by manually editing react.d.ts and replacing |
FYI: Looks like this has been resolved with #12114. |
I have two use cases that I cannot seem to type correctly in TypeScript. Both use cases involve functions that take a parameter of type "an object with any subset of the members of interface X".
Use case 1: options merging
Use case 2: React state
See also https://facebook.github.io/react/docs/component-api.html
A React component is a class with three generic parameters Props, State and Context. The base class defines a setState(newState: State) method. In reality though, the setState() method accepts any sub-type of State.
This becomes particularly painful when having multiple layers of inheritance in React components:
BaseWidget.tsx
The text was updated successfully, but these errors were encountered: