Confusing TypeScript error using generic types

Multi tool use
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.





Go on the setState() definition to see the argument type. And let me know.
– Becario Senior
Jul 3 at 7:53





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.

Qm9RF5tiO9g lyE MDRUlq90cI0xIjD29F1QL7Lvq,XkZo
eZUWCMpO,tO3Lx

Popular posts from this blog

PHP contact form sending but not receiving emails

Do graphics cards have individual ID by which single devices can be distinguished?

Create weekly swift ios local notifications