Home > OS >  TypeScript union as function parameter
TypeScript union as function parameter

Time:06-24

I have an app where I use a json structure to define the columns of a table.

Each column has a key and label property and an optional transformFunc property that takes a function that transforms the data to be displayed in the column.

This is the type for Column:

type Column = {
  key: string
  label: string
  transformFunc?: (value: string | number | Date) => string
};

transformFunc either takes a string, number or Date as an argument. However, I'm not able to properly type it this way:

const col: Column = {
  key: 'date',
  label: 'Date',
  transformFunc: (value: string) => value.substring(0, 5)  // TS2322: Type '(value: string) => string' is not assignable to type '(value: string | number | Date) => string'
}

How can I solve this?

I looked into generics but I don't see how to do this.

CodePudding user response:

In generic way

type Column<T extends string | number | Date> = {
  key: string
  label: string
  transformFunc?: (value: T) => string
};

const col: Column<string> = {
  key: 'date',
  label: 'Date',
  transformFunc: (value) => value.substring(0, 5)
}

CodePudding user response:

Because of your type definition, a transformFunc must accept all of the union's type, so you can't create a Column with a transformFunc accepting just one.

If you know what type of data a specific column will hold, you can use a type assertion in your function:

const col: Column = {
  key: 'date',
  label: 'Date',
  transformFunc: (value: string | number | Date) =>
    (value as string).substring(0, 5)
}

CodePudding user response:

Can you reverse this as follows?

Put the different method signatures in the Column interface.

Then implement in a way that conforms to those signatures

type Column = {
  key: string
  label: string
  transformFunc?:
    | ((value: string) => string)
    | ((value: number) => string)
    | ((value: Date) => string)  // <-- define the different function sigs
};


const col: Column = {
  key: 'date',
  label: 'Date',
  transformFunc: (value: number | Date) => String(value), // <-- set whatever types you need here
}

CodePudding user response:

After defining Column, you could have no need for any type when using it. You just use values, like 'date' and 'Date', give to transformFunc a function without any type, then use type narrowing to have what you want. Something like the below code.

See this TypeScript playgroud I created.

type Column = {
  key: string
  label: string
  transformFunc?: (value: string | number | Date) => string
};

const col: Column = {
  key: 'date',
  label: 'Date',
  transformFunc: (value) => {if (typeof value == "string") {return value.substring(0, 5)}else return ""} 
}
  • Related