Reputation: 1678
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
Upvotes: 5
Views: 7899
Reputation: 43138
The compiler message is actually quite clear: You have constrained the myComponent
function to only accept props with a resolved type such as string
, number
, string|number
, or never
. You have also used the same constraint placed on that function to also restrict what types myFunc
can receive (which at this point is whatever was passed into myComponent
).
The problem the compiler is trying to draw your attention to is that if myComponent
is called with Props<number>
, T
becomes restricted to only number
, which is also what myFunc
will be restricted to, therefore if you do myFunc('test');
you may be violating the current constraint on myFunc
which is that it only accepts number
types, not string
.
If you do not wish to adhere to this safeguard, you can shake off the restraints and allow both myFunc
and myComponent
to become contractually independent of each other, which allows you do what you originally wished to do:
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;
}
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 {};
}
Upvotes: 3
Reputation: 8340
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');
}
Upvotes: 3