#Typed function

41 messages · Page 1 of 1 (latest)

violet crescent
#

I created type for my function, but for some reason params are not type safe and intelisense doesn't tell me what params should be in func

signal gate
violet crescent
signal gate
#

I do not believe you can do that. 🤔 since the parameters are pretty much "optional" in a sense that you can either use them or not, you can also name them to anything, there is no strict rules for that so you cannot really "force" people to use your naming convention or to include those arguments when they define a function

violet crescent
#

@signal gate , thanks and sorry to ping you again but I seem to be a litlle confused on other thing. I have this types file:

type TReportTypeEnum = "report" | "dashboard";
type TWidgetTypeEnum = "card" | "barchart" | "piechart" | "linechart" | "table";
type TCardData = {
  value: number;
  changepercent: string;
};
type TBarChartData = {
  value: number;
  changepercent: string;
};
type TLineChartData = {
  value: number;
  changepercent: string;
};
type TPieChartData = {
  value: number;
  changepercent: string;
};
type TTableData = {
  value: number;
  changepercent: string;
};
type TWidgetsDataEnum =
  | TCardData
  | TBarChartData
  | TLineChartData
  | TPieChartData
  | TTableData;

export interface IReportConfig {
  integration: string;
  reportType: TReportTypeEnum;
  widgets: [
    {
      id: string;
      type: TWidgetTypeEnum;
      data: TWidgetsDataEnum;
      x: number;
      y: number;
      title: string;
    }
  ];
}

and i have this function ( screenshot )

#

and when I try to put this config as param in function, I get an error

#

here is this config file

#

how can I fix problem with not assignable thing ?

signal gate
signal gate
violet crescent
#

@signal gate Also, it should get different data type depending on widget type, for example, type of the widget is card, then it needs to have TCardData as data type

signal gate
# violet crescent yes

You need to parse the JSON file to validate it it indeed contains the correct model (type).
A schema validator would be the best to do that eg.: zod or if you "really" trust the source file, you can cast its type but I personally wouldn't do that.

signal gate
#
type ReportTypeEnum = "report" | "dashboard";

type WidgetTypeEnum = "card" | "barchart" | "piechart" | "linechart" | "table";

type CardData = {
  variant: 'CardData',
  value: number;
  changepercent: string;
};

type BarChartData = {
  variant: 'BarChartData',
  changepercent: string;
  exampleData: number:
};

type LineChartData = {
  variant: 'LineChartData',
  value: number;
  changepercent: string;
};

type PieChartData = {
  variant: 'PieChartData',
  value: number;
  changepercent: string;
};

type TableData = {
  variant: 'TableData',
  value: number;
  changepercent: string;
};

type AllowedWidgetDataVariant =
  | CardData
  | BarChartData
  | LineChartData
  | PieChartData
  | TableData;

type ReportConfigBase<
  ReportType extends ReportTypeEnum,
  WidgetType extends WidgetTypeEnum,
  WidgetData extends AllowedWidgetDataVariant
> = {
  integration: string;
  reportType: ReportType;
  widgets: [
    {
      id: string;
      type: WidgetType;
      data: WidgetData;
      x: number;
      y: number;
      title: string;
    }
  ];
}

type ReportCardConfig = ReportConfigBase<"report", "card", CardData>
type ReportBarChartConfig = ReportConfigBase<"report", "barchart", BarChartData>
type ReportPieChartConfig = ReportConfigBase<"report", "piechart", PieChartData>
type ReportLineChartConfig = ReportConfigBase<"report", "linechart", LineChartData>
type DashboardCardConfig = ReportConfigBase<"dashboard", "card", CardData>
type DashboardBarChartConfig = ReportConfigBase<"dashboard", "barchart", BarChartData>
type DashboardPieChartConfig = ReportConfigBase<"dashboard", "piechart", PieChartData>
type DashboardLineChartConfig = ReportConfigBase<"dashboard", "linechart", LineChartData>
#
export type AllowedReportConfig =
  | ReportCardConfig 
  | ReportBarChartConfig
  | ReportPieChartConfig
  | ReportLineChartConfig

export type AllowedDashboardConfig =
  | DashboardCardConfig
  | DashboardBarChartConfig
  | DashboardPieChartConfig
  | DashboardLineChartConfig

export type AllowedConfig = AllowedReportConfig | AllowedDashboardConfig
#

Then you can setup type guards if needed to differentiate between these types

#
const isReportConfig = (config: AllowedConfig) config is AllowedReportConfig => {
  return config.reportType === 'report'
}


const myTestConfig: AllowedConfig = {...}

if (isReportConfig(myTestConfig)) {
  myTestConfig // <-- type will become AllowedReportConfig
}

myTestConfig // <-- type will become AllowedDashboardConfig
violet crescent
#

Thanks, for your help, I'll try to figure out how it works now )

violet crescent
signal gate
#

You need to read the JSON from the file system and the content of the file can change anytime so you need to be safe and validate the data stored in that file.

violet crescent
#

okay, ty so much )

signal gate
violet crescent
#

@signal gate seems like it argues with type reporType for some reason. Do you know what could be the problem ?

violet crescent
#

also I changed cardData type so the data field would correspond

violet crescent
#

@signal gate and will your sollution tell exactly what data each element of widget array has ?

signal gate
signal gate
#

so using me example above:

const myTestConfig: AllowedConfig = {...}

if (isReportConfig(myTestConfig)) {
  myTestConfig // <-- type will become AllowedReportConfig

  myTestConfig.widgets.map(widget => {
    widget.type // type is CardData | BarChartData | PieChartData | LineChartData

    if (widget.type === 'card') {
        widget.data // type will become CardData
      return ... //
    }
    widget.type // type will be narrowed down to BarChartData | PieChartData | LineChartData
    
    if (widget.type === 'barchart') {
        widget.data // type will become BarChartData
      return ... //
    }
    widget.type // type will be narrowed down to PieChartData | LineChartData
    // etc...
  })
}
violet crescent
#

that's so cool

#

the whole typing of this thing is still confusing to me, as for example why do we extend in generic < > brackets

#

but it works and that's awesome

signal gate
# violet crescent the whole typing of this thing is still confusing to me, as for example why do w...

If we don't extends those types in the generic declaration, we are not restricting other developers to create some funky types.
eg.:

type MyStrictType<Name extends string, Age extends number> = {
  name: Name
  age: Age
}

type MyLooseType<Name, Age> = {
  name: Name
  age: Age
}

// STRICT TYPE
type StrictGeorge = MyStrictType<"George", 31> // This will work
type StrictEvilGeorge = MyStrictType<666, "Thousand"> // This will complain

// LOOSE TYPE
type LooseGeorge = MyLooseType<"George", 31> // This will work
type LooseEvilGeorge = MyLooseType<666, "Thousand"> // This will also work
violet crescent
signal gate