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)