-
Notifications
You must be signed in to change notification settings - Fork 13.2k
Closed
Labels
DuplicateAn existing issue was already createdAn existing issue was already created
Description
TypeScript Version: 2.1.4
The idea
I came up with this definition of React's setState, that should offer (under strictNullChecks) the following:
- accepting a state patch object with any combination of properties of the
Statetype, even without non-null properties specified - 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 operationkeyof { [P in K]: X }is equivalent to justK. For example,keyof Partial<T>is equivalent tokeyof T.
... I am afraid that it might only work because of a bug, for the following reasons:
- Shouldn't
nonNullable1?: number;be the same asnonNullable1: number | undefined;? If so, calling the function like thissetState({ nonNullable1: undefined })should report no error. - @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
- Is this behavior here to stay, or it results from a bug in TS, and
- If this particular behavior is by design, can this solution be considered a safe
setState()definition to use in React withstrictNullChecks?
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'.Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
DuplicateAn existing issue was already createdAn existing issue was already created