Reputation: 1500
I have the following code:
const mixed = {
validations: [] as any[],
formattings: [] as any[],
exceptions: [] as any[],
required(message?: string) {
this.validations.push({
name: 'required',
message: message || config.messages.mixed.required,
test: (value: string) => {
return value && value.trim() ? true : false
},
})
return this
},
// other methods that will be reusable
}
const string = () => ({
...mixed,
maxWords(maxWords: number, message?: string) {
type Params = { maxWords: number }
this.validations.push({
name: 'maxWords',
params: { maxWords },
message: message || config.messages.string.maxWords,
test: (value: string, { maxWords }: Params) => {
const wordCount = value.trim().split(' ').length
return wordCount <= maxWords
},
})
return this
},
trim() {
this.formattings.push({
name: 'trim',
format: (value: string) => {
return value.trim()
},
})
return this
},
})
const number = () => ({
...mixed,
positive(message?: string) {
this.validations.push({
name: 'positive',
message: message || config.messages.string.maxWords,
test: (value: string) => {
// make a validation
},
})
return this
},
})
const schema = {
string() {
return string()
},
number() {
return number()
},
// file, date, etc..
}
const form = {
name: schema.string().required().trim().maxWords(3),
age: schema.number().required().positive(),
}
Everything works perfectly in execution, the problem is that I am trying to build a form validation library and I need intellisense working on all methods.
Here's TS Playground so you can test it in real time.
the problem is in the typing of the returns of each function
Upvotes: 0
Views: 58
Reputation: 664356
You can use required(message?: string): this
if you declare the method type in an interface or class. Stripped down example:
interface Validation<T> {
message: string
test: (value: T) => boolean
}
interface FormField<T> {
validations: Validation<T>[];
required(message: string): this;
}
const mixed: FormField<unknown> = {
validations: [],
required(message) {
this.validations.push({
message,
test(value: string) {
return value.trim()
}
})
return this
}
}
interface StringField extends FormField<string> {
maxWords(maxWords: number, message: string): this;
}
const string = (): StringField => ({
...mixed as StringField, // this is a bit ugly, would work better if mixed() was a function or superclass
maxWords(maxWords, message) {
this.validations.push({
message,
test: value => value.trim().split(' ').length <= maxWords,
})
return this
}
})
interface NumberField extends FormField<number> {
positive(message: string): this;
}
const number = (): NumberField => ({
...mixed as NumberField,
positive(message) {
this.validations.push({
message,
test: value => value > 0,
})
return this
},
})
const form = {
name: string().required('missing name').maxWords(3, 'too few words'),
age: number().required('missing age').positive('must be born already'),
}
Upvotes: 1