Post

Conditionally Chain Methods in TypeScript

Photo by Chris Ried on Unsplash

I needed to dynamically create yup validations in TypeScript, which are accomplished by method chaining.

I only needed to chain .required in the case that requiredBool was true, as below:

const x = number()
.typeError(`age must be a number`)
.required(`age is required`) // Only run if requiredBool is true

The naive way to solve this that I don’t like would be:

let x = number()
.typeError(`age must be a number`)
if (requiredBool)
x = x.required(`age is required`) // Only runs if requiredBool is true

However, the above code does not follow the functional style and looks ugly for longer method chains, so I created an abstraction for this which you can define somewhere in your project to use:

export const chainInit = <InitialObject, TransformedObject>(value: InitialObject) => {
return {
if(condition: boolean, thanF: (param: InitialObject) => TransformedObject, elseF?: (param: InitialObject) => TransformedObject) {
return chainInit(condition ? thanF(value) : elseF ? elseF(value) : value);
},
chain(f: (param: InitialObject) => TransformedObject) {
return chainInit(f(value));
},
finish() {
return value;
},
};
};

Thus, it becomes more functional and cleaner in my opinion:

chainInit(number())
.chain(scma => scma.typeError(`age must be a number`))
.if(requiredBool, scma => scma.required(`age is required`))
.finish();
This post is licensed under CC BY 4.0 by the author.