Skip to content
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

Mapped types with strictNullChecks and React setState() - Could this be a reliable solution? #12801

Closed
vknez opened this issue Dec 9, 2016 · 2 comments
Labels
Duplicate An existing issue was already created

Comments

@vknez
Copy link

vknez commented Dec 9, 2016

TypeScript Version: 2.1.4

The idea

I came up with this definition of React's setState, that should offer (under strictNullChecks) the following:

  1. accepting a state patch object with any combination of properties of the State type, even without non-null properties specified
  2. when a non-null property is present in the state patch object, TS must not allow setting it to null | undefined
function setState(_patch: {[P in keyof Partial<State>]: State[P]}): void {
}
interface State {
    nonNullable1: number;
    nonNullable2: string;
    nullable?: string;
}

Potential issues

It seems that this satisfies my requirements, as you can see below in the code extract, but when I look at the mapped type definition:

{
    nonNullable1?: number;
    nonNullable2?: string;
    nullable?: string | undefined;
}

... and one particular statement in #12351:

The PR furthermore adds the following rules:
The operation keyof { [P in K]: X } is equivalent to just K. For example, keyof Partial<T> is equivalent to keyof T.

... I am afraid that it might only work because of a bug, for the following reasons:

  1. Shouldn't nonNullable1?: number; be the same as nonNullable1: number | undefined;? If so, calling the function like this setState({ nonNullable1: undefined }) should report no error.
  2. @ahejlsberg's comment does not hold here, because if I change the definition to:
    _patch: {[P in keyof State]: State[P]}, TS complains in all the function calls below in the code extract and the mapped type definition becomes:
{
    nonNullable1: number;
    nonNullable2: string;
    nullable?: string | undefined;
}

Questions

  1. Is this behavior here to stay, or it results from a bug in TS, and
  2. If this particular behavior is by design, can this solution be considered a safe setState() definition to use in React with strictNullChecks?

Full code example

interface State {
    nonNullable1: number;
    nonNullable2: string;
    nullable?: string;
}

function setState(_patch: {[P in keyof Partial<State>]: State[P]}): void {
}

setState({

});
// passes

setState({
    nullable: "test",
});
// passes

setState({
    nullable: undefined,
});
// passes

setState({
    nonNullable1: 1,
});
// passes

setState({
    nonNullable1: undefined,
});
// Argument of type '{ nonNullable1: undefined; }' is not assignable to parameter of type '{ nonNullable1?: number; nonNullable2?: string; nullable?: string | undefined; }'.
// Types of property 'nonNullable1' are incompatible. Type 'undefined' is not assignable to type 'number'.
@ahejlsberg
Copy link
Member

See my comment in #12793.

@vknez
Copy link
Author

vknez commented Dec 12, 2016

Thanks, that looks good.

@vknez vknez closed this as completed Dec 12, 2016
@RyanCavanaugh RyanCavanaugh added the Duplicate An existing issue was already created label Dec 12, 2016
@microsoft microsoft locked and limited conversation to collaborators Jun 19, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Duplicate An existing issue was already created
Projects
None yet
Development

No branches or pull requests

3 participants