Confusing TypeScript error using generic types

Multi tool use
Confusing TypeScript error using generic types
I have a setup like this:
export interface IListItem<TData = any> {
id: string;
isNew: boolean;
isOpen: boolean;
data: TData;
}
export interface IListStore<TItem> {
allowAddNew: boolean;
allowDelete: boolean;
items: IListItem<TItem>;
}
export abstract class ListStore<TItem extends any, TState extends IListStore<TItem>> {
public state: TState;
public setState(newState: Partial<TState>): void {
}
public myMethod(): void {
const items: IListItem<TItem> = ;
this.setState({ // error on
items, // these three
}); // lines
}
}
But I get this error around the setState
method call in myMethod
:
setState
myMethod
Argument of type '{ items: IListItem<TItem>; }' is not assignable to
parameter of type 'Partial<TState>'.
Which is odd because it seems a perfectly correct assignment to me?
Using VS Code v1.24.1 and TypeScript v2.9.1.
You mean like this:
(method) ListStore<TItem extends any, TState extends IListStore<TItem>>.setState(newState: Partial<TState>): void
– Anupheaus
Jul 3 at 7:54
(method) ListStore<TItem extends any, TState extends IListStore<TItem>>.setState(newState: Partial<TState>): void
1 Answer
1
This is a limitation of mapped types with generic parameters and you can read why the team choses not to implement this here, but a summary would be:
The [...] error is by design because for a type parameter T extends C, T is assignable to C, but C is not assignable to T. In this specific case, a GenericSubValue is not assignable to a Partial because the actual type substituted for TValueSub might have properties that are further derived than those in GenericSubValue.
So for example if we have a field, the field can be of a more specialized type, and so the value we asume is valid for T
might actually not be:
T
function test<T extends { foo: string }>(c: (p: Partial<T>) => void) : void {
c({
foo: "" // foo can be string but can be a more specialized type, such as a string literal type
})
}
// This needs to works, but since foo is more specialized, test can't know what a valid value for Partial<T> is
test<{ foo: 'just this value'}>(c=> {});
The simplest solution, if you want to do this (and have potentially have the class not work correctly for all derived types) is to use a type assertion:
public myMethod(): void {
const items: IListItem<TItem> = ;
this.setState({
items,
} as Partial<TState>);
}
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.
Go on the setState() definition to see the argument type. And let me know.
– Becario Senior
Jul 3 at 7:53