I have a problem with understanding of Typescript type describing my validation functions. These are the types of functions that I use with my code:
type ValidationFunctionType = {
fieldName: string;
fields: string;
};
type MaxYearType = ValidationFunctionType & { fieldValue: Date; args: { maxYear: Date } };
type MinLengthType = ValidationFunctionType & {
fieldValue: string;
args: { minLength: number };
};
type MinNumberType = ValidationFunctionType & {
fieldValue: number;
args: { minNumber: number };
};
Then I create a union type for all the functions:
export type ValidationFunctionsType =
| (({}: MinLengthType) => string)
| (({}: MinNumberType) => string)
| (({}: MaxYearType) => string);
These are the functions that I use with these function types:
const minLength = ({ fieldName, fieldValue, fields, args }: MinLengthType) => {
return '';
};
const maxYear = ({ fieldName, fieldValue, fields, args }: MaxYearType) => {
return '';
};
const minNumber = ({ fieldName, fieldValue, fields, args }: MinNumberType) => {
return '';
};
And when I create an array with the above functions and use them in map:
const validationFunction: { func: ValidationFunctionsType}[] = [{
func: minLength
}, { func: maxYear}];
validationFunction.map(data => data.func({ fieldName: 'adfa', fieldValue: 'asdda', fields: 'sd', args: {
minLength: 5
} }));
I get the error message for field fieldName:
(property) fieldValue: never Type 'string' is not assignable to type 'never'.(2322) input.tsx(9, 2): The expected type comes from property 'fieldValue' which is declared here on type 'ValidationFunctionType & { fieldValue: string; args: { minLength: number; }; } & { fieldValue: number; args: { minNumber: number; }; } & { fieldValue: Date; args: { ...; }; }'
And for args field:
(property) args: { minLength: number; } & { minNumber: number; } & { maxYear: Date; } Type '{ minLength: number; }' is not assignable to type '{ minLength: number; } & { minNumber: number; } & { maxYear: Date; }'. Property 'minNumber' is missing in type '{ minLength: number; }' but required in type '{ minNumber: number; }'.(2322)
Why these types for field args and fieldName are connected with & operator instead of | operator? How to create a type for these functions which will be correct and more generic?
The whole code example in TS playground: Code
UPDATE
What I want to achieve in this example is to have a correctly designed type for all functions used for validation.
This type seems to work for Typescript:
type ValidationFunctionType = ({fieldName, fields, fieldValue, args}: MinLengthType | MinNumberType | MaxYearType) => string;
Working example But I'm not sure if it is the correct solution. Every function needs validation of fieldName and args type at the beginning.
CodePudding user response:
This seems to be a classic case of function overloading.
In your case, you should implement the signatures:
function validate(fieldName: string, fields: string, fieldValue: Date; args: { maxYear: Date }):string;
function validate(fieldName: string, fields: string, fieldValue: string; args: { maxYear: number }):string;
Finally, your implementation of validate
should support every case - you can use type guard for type checking
Reference for function overloading: https://www.typescriptlang.org/docs/handbook/2/functions.html#function-overloads
CodePudding user response:
data.func({ fieldName: 'adfa', fieldValue: 'asdda', fields: 'sd', args: {
minLength: 5
}}
You're passing in values here that make sense if the function is expecting a MinLengthType
. But since data.func
is a ValidationFunctionsType
, the type doesn't actually show that that's the expected data. The function might instead be expecting a MinNumberType
or a MaxYearType
, and the object you've passed would be an error for those, hence typescript shows an error.
Since there's 3 possible functions you might be dealing with, typescript will only allow you to pass in values that match all 3 functions. Ie, you can pass in the intersection of all 3 types: MinLengthType & MinNumberType & MaxYearType
. Unfortunately, that intersection is impossible to obey because it requires mutually exclusive things like fieldValue
being a string
, a number
, and a Date
simultaneously. So there is no way to legally call data.func
.
As for how to fix this... I'm not really sure what you're hoping to achieve from this code, so i may need more details. If you receive a function that expects, say, a MaxYearType
, what do you want to do? Call the function with some alternate data; not call it at all; something else? Also, how do you intend to identify which function variant you have?