Home > Back-end >  generic doen't check types between two property
generic doen't check types between two property

Time:12-22

type ComponentType = (...args: any) => any;

type PlatformNotificationProps<TIcon extends ComponentType = ComponentType> = {
  component: TIcon;
  arg: Parameters<TIcon>[0];
};

const PlatformNotification = (props: PlatformNotificationProps) => {};

const Icon = (name: string) => '';

const result = PlatformNotification({
  component: Icon,
  arg: 100,
});

In this case or 'arg' is incorrect and should be a string, or component is incorrect and should accept number instead string. I expecting to see error in console, but everything is ok.

How I can write types for this case?

CodePudding user response:

When using generics, all types along the chain need to pass over the generic arguments.

Since you are defaulting the arguments in PlatformNotificationProps and then using that type without configuring it, TS will not know to associate the arguments from your function to those of the generic

Here's one way you can do it by having all elements in your chain to be configurable

type Fn<Args extends any[] = any[]> = (...args: Args) => any;

type PlatformNotificationProps<Args extends any[], TIcon extends Fn<Args>> = {
  component: TIcon;
  arg: Parameters<TIcon>[0];
};

const PlatformNotification = <Args extends any[] = any[], Comp extends Fn<Args> = Fn<Args> >(props: PlatformNotificationProps<Args, Comp>) => {};

const Icon = (name: string) => '';

const result = PlatformNotification({
  component: Icon,
  arg: 100,
});

CodePudding user response:

The major problem is that you are assigning a default generic to PlatformNotificationProps:

type PlatformNotificationProps<TIcon extends ComponentType = ComponentType> = {
...

When you call this type without a proper generic type, typescript can only infer it to be of ComponentType, this is why arg can accept numbers, because it is actually typed as any:

const result = PlatformNotification({
  component: Icon,
  arg: 100,
// ^? (property) arg: any
});

The same for component actually:

const result = PlatformNotification({
  component: () => null, // no errors
  arg: 100,
});

In order to fix this, call PlatformNotificationProps with a type:

const PlatformNotification = (props: PlatformNotificationProps<typeof Icon>) => {};

And now:

const result = PlatformNotification({
  component: Icon,
  arg: 100, // error: type `number` is not assignable to `string`
});

CodePudding user response:

You have defined PlatformNotification as a non-generic function, don't expect it to check types

const PlatformNotification = (props: PlatformNotificationProps) => {};
//    ^?
// const PlatformNotification: (props: PlatformNotificationProps</*default*/ComponentType>) => void

const result = PlatformNotification({
  component: Icon,
// ^?
// (property) component: ComponentType
  arg: 100,
// ^?
// (property) arg: any
});

Just make it generic and it'll work

const PlatformNotification = <TIcon extends ComponentType>(props: PlatformNotificationProps<TIcon>) => {};
  • Related