How to fix "but 'T' could be instantiated with a different subtype of constraint ."

Viewed 2375

myFunc can take either string or number But since argument is defined as T gives error when a string is passed.

interface Props<T> {
  items: T[],
  onValueChange: (vals: T[]) => void;
}

export const myComponent = <T extends string | number>(props: Props<T>) => {

  const {
    items = [],
    onValueChange
  } = props;

  const myFunc = (item: T) => {
    //do something
    console.log(item);
    onValueChange([item])
  }

  items.map(item => myFunc(item));

  myFunc('test');

}

Error

Argument of type 'string' is not assignable to parameter of type 'T'.
  'string' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'string | number'.

How to fix this?

See in: TS Playground

2 Answers
interface Props<T> {
  items: T[],
  onValueChange: (vals: T[]) => void;
}

type ItemType = string | number;
export const myComponent = (props: Props<ItemType>) => {

  const {
    items = [],
    onValueChange
  } = props;

  const myFunc = (item: ItemType) => {
    //do something
    console.log(item);
    onValueChange([item])
  }

  items.map(item => myFunc(item));

  myFunc('test');
}

Another way:

interface Props<T> {
  items: T[],
  onValueChange: (vals: T[]) => void;
}

// For typing to work
declare namespace React {
  type FC<T> = (props: T) => {};
};

export const myComponent: React.FC<Props<string | number>> = ({items = [], onValueChange}) => {

  const myFunc = (item: string | number) => {
    //do something
    console.log(item);
    onValueChange([item])
  }

  items.map(item => myFunc(item));

  myFunc('test');

  return {};
}

If it suites your case you can make the type constraint a bit more strict:

export const myComponent = <T extends Props<string | number>>(props: T) => {

  const {
    items = [],
    onValueChange
  } = props;

  const myFunc = (item: string | number) => {
    //do something
    console.log(item);
    onValueChange([item])
  }

  items.map(item => myFunc(item));

  myFunc('test');
}

playground link

Related