How can I make the compiler understand that the return type of the parse
method is linked to the input of the serialize
method and it is dynamic?
type QUESTION = {
parse: (value: string) => any
serialize: (value: ReturnType<QUESTION['parse']>) => string
}
const idsQuestions: QUESTION[] = [
{
parse: (input) => input.split('\n'),
serialize: (ids) => ids.join('\n') // expect ids to be interpreted as string[]
},
{
parse: (input) => input.split('\n').reduce((acc, id) => ({
...acc,
[id]: true,
}), {}),
serialize: (ids) => Object.keys(ids).join('\n') // expect ids to be interpreted as { [string] => boolean }
}
]
// expect this to throw an error on build
const questionWithError: QUESTION = {
parse: () => false, // return type is boolean
serialize: (ids) => ids.join('\n') // but ids is not interpreted as boolean, so compiler doens't give an error
}
I've tried some uses of generics and unknown
, but could not make it work.
Tried to use infer
also, but could not understand exactly how to work with it
I could have something hardcoded like this, but I wanted it to be dynamic
type QUESTION<T> = {
parse: (value: string) => T
serialize: (value: T) => string
}
const idsQuestions: [
QUESTION<string[]>,
QUESTION<{ [k: string]: boolean }>,
] = [
{
parse: (input) => input.split('\n'),
serialize: (ids) => ids.join('\n') // expect ids to be interpreted as string[]
},
{
parse: (input) => input.split('\n').reduce((acc, id) => ({
...acc,
[id]: true,
}), {}),
serialize: (ids) => Object.keys(ids).join('\n') // expect ids to be interpreted as { [string] => boolean }
}
]
CodePudding user response:
You need to use genric-type
.
With this feature, you can tie between Types dynamically
interface Question<T> {
parse: (value: string) => T
serialize: (value: T) => string
}
const idsQuestion: Question<string[]> = {
parse: (input) => input.split('\n'),
serialize: (ids) => ids.join('\n') // expect ids to be interpreted as string[]
}
// expect this to throw an error on build
const questionWithError: Question<boolean> = {
parse: () => false, // return type is boolean
serialize: (ids) => ids.join('\n') // the transpiler will show an error
}
CodePudding user response:
I don't think what you're trying to achieve is doable without some helper functions or making it excessively verbose. Make a function that could help determine what T
should be.
type QUESTION<T> = {
parse: (value: string) => T
serialize: (value: T) => string
}
function QUESTION<T>(parse: (value: string) => T, serialize: (value: T) => string): QUESTION<T> {
return { parse, serialize };
}
const idsQuestions = [
QUESTION(
(input) => input.split('\n'),
(ids) => ids.join('\n') // expect ids to be interpreted as string[]
),
QUESTION(
(input) => input.split('\n').reduce((acc, id) => ({
...acc,
[id]: true,
}), {} as Record<string, boolean>),
(ids) => Object.keys(ids).join('\n') // expect ids to be interpreted as { [string] => boolean }
)
] as const;