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 ""}
}