indapublic
indapublic

Reputation: 2328

How to override generics correctly in Typescript

We have ancestor class with some properties (example with React).

export interface AncestorProps<T> {
    ...    
}

export class Ancestor<T> extends React.Component<AncestorProps<T>> {    
}

How to override child component correctly?

interface DescendentProps extends AncestorProps {
    someFunction: () => void;
}

export class Descendent<T> extends Ancestor<DescendentProps<T>> {
}

because not working, so I received this error (I remind you that this is React):

[ts] Type 'Readonly<{ children?: ReactNode; }> & Readonly>>' has no property 'someFunction' and no string index signature.

Example

Upvotes: 0

Views: 528

Answers (1)

Estus Flask
Estus Flask

Reputation: 222548

The problem with these generics is that they break the convention for React.Component to accept props and state as generic parameters. Parent class cannot be extended like Ancestor<DescendentProps<T>> because generic parameter is not props type in Ancestor but something else.

A fix would be to redefine props type in child class:

export interface AncestorProps<T> {}

export class Ancestor<T> extends React.Component<AncestorProps<T>> {}

interface DescendentProps<T> extends AncestorProps<T> {
    someFunction: () => void;
}

export class Descendent<T> extends Ancestor<T> {
  props!: DescendentProps<T>;
}

A proper way to make this hierarchy extendable is to consistently follow the convention for prop and state generic parameters. If there's no need for T parameter in AncestorProps<T>, it should be discarded:

export interface AncestorProps {}

export class Ancestor<P extends AncestorProps, S = {}> extends React.Component<P, S> {}

interface DescendentProps extends AncestorProps {
    someFunction: () => void;
}

export class Descendent<P extends DescendentProps, S = {}> extends Ancestor<P, S> {}

Upvotes: 1

Related Questions