In this article, You can find some type validation techniques.
Let's start with simple function
Assume, our function argument should be always some CSS value. For example: 100px, 10rem, 50% etc ...
First of all we should check if value ends with some allowed measure units:
type Units = 'px' | 'rem' | '%';
Now, we should be able to split our measure units into two parts: number and unit
type Units = 'px' | 'rem' | '%';
type IsValidCSS<T extends string> = T extends `${number}${Units}` ? true : false;
type Result = IsValidCSS<'10px'> // true
type Result2 = IsValidCSS<'10p'> // false
Lets write generic validator:
type Units = 'px' | 'rem' | '%';
type IsValidCSS<T extends string> = T extends `${number}${Units}` ? true : false;
type Validator<T extends boolean> = T extends true ? [] : [never];
type Test = Validator<IsValidCSS<'10px'>> // []
Please, give me a minute, I will explain why we need an array as a return type from Validator
Let's try it
const foo = <T,>(arg: T, ...validation: Validator<IsValidCSS<T>>) => {}
foo('10px'); // error
Still does not work, because argument is infered to string instead of literal 10px
.
In order to fix it, we should apply additional constraints to the generic type:
const foo = <T extends string>(arg: T, ...validation: Validator<IsValidCSS<T>>) => {}
foo('10px'); // ok
foo('10%'); // ok
foo('10p'); // error
Is it possible to apply several validators?
Assume, we are not allowed to use 99
in our CSS
type Units = 'px' | 'rem' | '%';
type IsValidCSS<T> = T extends `${number}${Units}` ? true : false;
type StringNumber<T extends number> = `${T}`;
type IsAllowedNumber<T> =
T extends `${infer Num}${Units}`
? Num extends StringNumber<99>
? false
: true
: false;
type Validator<T extends boolean> =
T extends true
? []
: ['Dear developer, please use valid CSS values'];
const foo = <T extends string>
(
arg: T,
...validation: [...Validator<IsValidCSS<T>>, ...Validator<IsAllowedNumber<T>>]
) => { }
foo('100px'); // ok
foo('99px'); // expected error
Each time, when Validator
fails, it returns [never]
and because we are using rest operator it evaluates to never
.
So if Validator
has failed, TS expects second argument which is never
.
That's all.
Top comments (0)