Joi рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рдЯрд╛рдЗрдкрд╕реНрдХреНрд░рд┐рдкреНрдЯ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рд╕рддреНрдпрд╛рдкрди

рдПрдХ рд╣реА рдХреЛрдб рдХреЛ рдХрдИ рдмрд╛рд░ рд▓рд┐рдЦрдиреЗ рдкрд░ рджреЛ рджрд┐рди рдХреИрд╕реЗ рдмрд┐рддрд╛рдПрдВ рдЗрд╕рдХреА рдХрд╣рд╛рдиреАред


Joi & TypeScript. A love story


рдкреНрд░рд╡рд┐рд╖реНрдЯрд┐


рдЗрд╕ рд▓реЗрдЦ рдореЗрдВ, рдореИрдВ рд╣рд╛рдкреА, рдЬреЙрдп рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рд╡рд┐рд╡рд░рдг рдЫреЛрдбрд╝ рджреЗрддрд╛ рд╣реВрдВ, рд░реВрдЯрд┐рдВрдЧ рдФрд░ validate: { payload: ... } , рдпрд╣ рдЕрд░реНрде рджреЗрддреЗ рд╣реБрдП рдХрд┐ рдЖрдк рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рд╕рдордЭрддреЗ рд╣реИрдВ рдХрд┐ рдпрд╣ рдХреНрдпрд╛ рд╣реИ, рд╕рд╛рде рд╣реА рд╕рд╛рде рд╢рдмреНрджрд╛рд╡рд▓реА, рдПрдХ рд▓рд╛ "рдЗрдВрдЯрд░рдлреЗрд╕", "рдкреНрд░рдХрд╛рд░" рдФрд░ рдЬреИрд╕реЗ ред рдореИрдВ рдЖрдкрдХреЛ рдХреЗрд╡рд▓ рдПрдХ рдЯрд░реНрди-рдЖрдзрд╛рд░рд┐рдд рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдмрддрд╛рддрд╛ рд╣реВрдВ, рди рдХрд┐ рд╕рдмрд╕реЗ рд╕рдлрд▓ рд░рдгрдиреАрддрд┐, рдЗрди рдЪреАрдЬреЛрдВ рдореЗрдВ рдореЗрд░рд╛ рдкреНрд░рд╢рд┐рдХреНрд╖рдгред


рдереЛрдбрд╝реА рдкреГрд╖реНрдарднреВрдорд┐


рдЕрдм рдореИрдВ рдкрд░рд┐рдпреЛрдЬрдирд╛ рдкрд░ рдХреЗрд╡рд▓ рдмреИрдХреЗрдВрдб рдбреЗрд╡рд▓рдкрд░ (рдЕрд░реНрдерд╛рддреН, рдХреЛрдб рд▓рд┐рдЦрдирд╛) рд╣реВрдВред рдХрд╛рд░реНрдпрдХреНрд╖рдорддрд╛ рд╕рд╛рд░ рдирд╣реАрдВ рд╣реИ, рд▓реЗрдХрд┐рди рдореБрдЦреНрдп рд╕рд╛рд░ рд╡реНрдпрдХреНрддрд┐рдЧрдд рдбреЗрдЯрд╛ рдХреЗ рд╕рд╛рде рдПрдХ рд▓рдВрдмрд╛ рдкреНрд░реЛрдлрд╝рд╛рдЗрд▓ рд╣реИред рдХреЛрдб рдХреА рдЧрддрд┐ рдФрд░ рдЧреБрдгрд╡рддреНрддрд╛ рд╕реНрдХреНрд░реИрдЪ рд╕реЗ рдкрд░рд┐рдпреЛрдЬрдирд╛рдУрдВ рдкрд░ рд╕реНрд╡рддрдВрддреНрд░ рд░реВрдк рд╕реЗ рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рдореЗрд░реЗ рдЫреЛрдЯреЗ рдЕрдиреБрднрд╡ рдкрд░ рдЖрдзрд╛рд░рд┐рдд рд╣реИ, рдпрд╣рд╛рдВ рддрдХ тАЛтАЛрдХрд┐ рдЬреЗрдПрд╕ (рдХреЗрд╡рд▓ 4 рд╡реЗрдВ рдорд╣реАрдиреЗ) рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдХрд╛ рдХрдо рдЕрдиреБрднрд╡, рдФрд░ рд╕рд╛рде рд╣реА, рдмрд╣реБрдд рдЯреЗрдврд╝реЗ-рдореЗрдврд╝реЗ рддрд░реАрдХреЗ рд╕реЗ, рдореИрдВ рдЯрд╛рдЗрдкрд╕реНрдХреНрд░рд┐рдкреНрдЯ (рдЗрд╕рдХреЗ рдмрд╛рдж: рдЯреАрдПрд╕) рдореЗрдВ рд▓рд┐рдЦрддрд╛ рд╣реВрдВред рддрд┐рдерд┐рдпрд╛рдВ рд╕рдВрдХреБрдЪрд┐рдд рд╣реИрдВ, рд░реЛрд▓ рд╕рдВрдкреАрдбрд╝рд┐рдд рд╣реИрдВ, рд╕рдВрдкрд╛рджрди рд▓рдЧрд╛рддрд╛рд░ рдЖ рд░рд╣реЗ рд╣реИрдВ рдФрд░ рдпрд╣ рдкрд╣рд▓реЗ рд╡реНрдпрд╛рдкрд╛рд░ рддрд░реНрдХ рдХреЛрдб рд▓рд┐рдЦрдиреЗ рдХреЗ рд▓рд┐рдП рдирд┐рдХрд▓рддрд╛ рд╣реИ, рдФрд░ рдлрд┐рд░ рдКрдкрд░ рд╕реЗ рдЗрдВрдЯрд░рдлреЗрд╕ред рдлрд┐рд░ рднреА, рдПрдХ рддрдХрдиреАрдХреА рдХрд░реНрддрд╡реНрдп рдХреИрдк рдХреЛ рдкрдХрдбрд╝рдиреЗ рдФрд░ рджреЛрд╣рди рдХрд░рдиреЗ рдореЗрдВ рд╕рдХреНрд╖рдо рд╣реИ, рдЬреЛ рд▓рдЧрднрдЧ, рд╣рдорд╛рд░реЗ рд╕рд╛рде рд╣реБрдЖ рд╣реИред


рдкрд░рд┐рдпреЛрдЬрдирд╛ рдкрд░ 3 рдорд╣реАрдиреЗ рдХреЗ рдХрд╛рдо рдХреЗ рдмрд╛рдж, рдореИрдВ рдЖрдЦрд┐рд░рдХрд╛рд░ рдЕрдкрдиреЗ рд╕рд╣рдпреЛрдЧрд┐рдпреЛрдВ рдХреЗ рд╕рд╛рде рдПрдХ рд╣реА рд╢рдмреНрджрдХреЛрд╖ рдкрд░ рд╕реНрд╡рд┐рдЪ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╕рд╣рдордд рд╣реЛ рдЧрдпрд╛, рддрд╛рдХрд┐ рдСрдмреНрдЬреЗрдХреНрдЯ рдХреЗ рдЧреБрдгреЛрдВ рдХрд╛ рдирд╛рдо рджрд┐рдпрд╛ рдЬрд╛рдП рдФрд░ рд╣рд░ рдЬрдЧрд╣ рд╕рдорд╛рди рд▓рд┐рдЦрд╛ рдЬрд╛рдПред рдЗрд╕ рд╡реНрдпрд╡рд╕рд╛рдп рдХреЗ рддрд╣рдд, рдирд┐рд╢реНрдЪрд┐рдд рд░реВрдк рд╕реЗ, рдореИрдВрдиреЗ рдПрдХ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рд▓рд┐рдЦрдиреЗ рдХрд╛ рдмреАрдбрд╝рд╛ рдЙрдард╛рдпрд╛ рдФрд░ рджреЛ рд╡реНрдпрд╛рд╡рд╕рд╛рдпрд┐рдХ рджрд┐рдиреЛрдВ рдХреЗ рд▓рд┐рдП рдЗрд╕рдХреЗ рд╕рд╛рде рдордЬрдмреВрддреА рд╕реЗ рдлрдВрд╕ рдЧрдпрд╛ред


рд╕рдорд╕реНрдпрд╛


рдПрдХ рд╕рд╛рдзрд╛рд░рдг рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдкреНрд░реЛрдлрд╛рдЗрд▓ рдПрдХ рдЕрдореВрд░реНрдд рдЙрджрд╛рд╣рд░рдг рд╣реЛрдЧрд╛ред


  • рдкрд╣рд▓реЗ рдПрдХ рдЕрдЪреНрдЫреЗ рдбреЗрд╡рд▓рдкрд░ рдХрд╛ рд╢реВрдиреНрдп рдХрджрдо: рдбреЗрдЯрд╛ рдХрд╛ рд╡рд░реНрдгрди рдХрд░реЗрдВ рдкрд░реАрдХреНрд╖рдг рд▓рд┐рдЦреЗрдВ;
  • рдкрд╣рд▓рд╛ рдХрджрдо: рдкрд░реАрдХреНрд╖рдг рд▓рд┐рдЦреЗрдВ рдбреЗрдЯрд╛ рдХрд╛ рд╡рд░реНрдгрди рдХрд░реЗрдВ
  • рдФрд░ рдЗрд╕реА рддрд░рд╣ред

рдорд╛рди рд▓реАрдЬрд┐рдП рдХрд┐ рдЗрд╕ рдХреЛрдб рдХреЗ рд▓рд┐рдП рдкрд░реАрдХреНрд╖рдг рдкрд╣рд▓реЗ рд╣реА рд▓рд┐рдЦреЗ рдЬрд╛ рдЪреБрдХреЗ рд╣реИрдВ, рдпрд╣ рдбреЗрдЯрд╛ рдХрд╛ рд╡рд░реНрдгрди рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдмрдирд╛ рд╣реБрдЖ рд╣реИ:


 interface IUser { name: string; age: number; phone: string | number; } const aleg: IUser = { name: 'Aleg', age: 45, phone: '79001231212' }; 

рдЦреИрд░, рдпрд╣рд╛рдВ рд╕рдм рдХреБрдЫ рд╕реНрдкрд╖реНрдЯ рдФрд░ рдмреЗрд╣рдж рд╕рд░рд▓ рд╣реИред рдпрд╣ рд╕рдм рдХреЛрдб, рдЬреИрд╕рд╛ рдХрд┐ рд╣рдо рдпрд╛рдж рдХрд░рддреЗ рд╣реИрдВ, рдмреИрдХрдПрдВрдб рдкрд░ рдпрд╛ рдмрд▓реНрдХрд┐, рдПрдкреА рдореЗрдВ, рдЕрд░реНрдерд╛рддреН, рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдиреЗрдЯрд╡рд░реНрдХ рдкрд░ рдЖрдП рдбреЗрдЯрд╛ рдХреЗ рдЖрдзрд╛рд░ рдкрд░ рдмрдирд╛рдпрд╛ рдЧрдпрд╛ рд╣реИред рдЗрд╕ рдкреНрд░рдХрд╛рд░, рд╣рдореЗрдВ рдЖрдиреЗ рд╡рд╛рд▓реЗ рдбреЗрдЯрд╛ рдХреЛ рдорд╛рдиреНрдп рдХрд░рдиреЗ рдФрд░ рдЗрд╕рдореЗрдВ рдЬреЙрдп рдХреА рдорджрдж рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ:


 const joiUserValidator = { name: Joi.string(), age: Joi.number(), phone: Joi.alternatives([Joi.string(), Joi.number()]) }; 

"рдорд╛рдереЗ рдкрд░" рд╕рдорд╛рдзрд╛рди рддреИрдпрд╛рд░ рд╣реИред рдЗрд╕ рджреГрд╖реНрдЯрд┐рдХреЛрдг рдХрд╛ рд╕реНрдкрд╖реНрдЯ рдорд╛рдЗрдирд╕ рдпрд╣ рд╣реИ рдХрд┐ рд╕рддреНрдпрд╛рдкрдирдХрд░реНрддрд╛ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рд╕реЗ рдкреВрд░реА рддрд░рд╣ рд╕реЗ рддрд▓рд╛рдХрд╢реБрджрд╛ рд╣реИред рдпрджрд┐ рдЖрд╡реЗрджрди рдХреЗ рдЬреАрд╡рди рдХреЗ рджреМрд░рд╛рди рдлрд╝реАрд▓реНрдб рдмрджрд▓рддреЗ рд╣реИрдВ / рдЙрдирдХреЗ рдкреНрд░рдХрд╛рд░ рдмрджрд▓рддреЗ рд╣реИрдВ, рддреЛ рдЗрд╕ рдкрд░рд┐рд╡рд░реНрддрди рдХреЛ рдореИрдиреНрдпреБрдЕрд▓ рд░реВрдк рд╕реЗ рдЯреНрд░реИрдХ рдХрд░рдиреЗ рдФрд░ рд╕рддреНрдпрд╛рдкрдирдХрд░реНрддрд╛ рдореЗрдВ рдЗрдВрдЧрд┐рдд рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрдЧреАред рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдХреБрдЫ рдЧрд┐рд░рдиреЗ рддрдХ рдРрд╕реЗ рдЬрд┐рдореНрдореЗрджрд╛рд░ рдбреЗрд╡рд▓рдкрд░реНрд╕ рдирд╣реАрдВ рд╣реЛрдВрдЧреЗред рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, рд╣рдорд╛рд░реА рдкрд░рд┐рдпреЛрдЬрдирд╛ рдореЗрдВ рдкреНрд░рд╢реНрдирд╛рд╡рд▓реА рдореЗрдВ рдШреЛрдВрд╕рд▓реЗ рдХреЗ рддреАрди рд╕реНрддрд░реЛрдВ рдкрд░ 50+ рдХреНрд╖реЗрддреНрд░ рд╣реЛрддреЗ рд╣реИрдВ рдФрд░ рдЗрд╕реЗ рд╕рдордЭрдирд╛ рдмрд╣реБрдд рдореБрд╢реНрдХрд┐рд▓ рд╣реИ, рдпрд╣рд╛рдВ рддрдХ тАЛтАЛрдХрд┐ рджрд┐рд▓ рд╕реЗ рд╕рдм рдХреБрдЫ рдЬрд╛рдирддреЗ рд╣реБрдП рднреАред


рд╣рдо рдХреЗрд╡рд▓ const joiUserValidator: IUser рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдирд╣реАрдВ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рдХреНрдпреЛрдВрдХрд┐ Joi рдЕрдкрдиреЗ рдбреЗрдЯрд╛ рдкреНрд░рдХрд╛рд░реЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реИ, рдЬреЛ рдЯрд╛рдЗрдк рдХрд░рддреЗ рд╕рдордп рддреНрд░реБрдЯрд┐рдпреЛрдВ рдХреЛ рдЙрддреНрдкрдиреНрди рдХрд░рддрд╛ рд╣реИ Type 'NumberSchema' is not assignable to type 'number' ред рд▓реЗрдХрд┐рди рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдкрд░ рд╕рддреНрдпрд╛рдкрди рдХрд░рдиреЗ рдХрд╛ рдПрдХ рддрд░реАрдХрд╛ рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдП?


рд╢рд╛рдпрдж рдореИрдВрдиреЗ рдЗрд╕реЗ рд╕рд╣реА рдврдВрдЧ рд╕реЗ Google рдирд╣реАрдВ рдХрд┐рдпрд╛ рд╣реИ, рдпрд╛ рдЦрд░рд╛рдм рддрд░реАрдХреЗ рд╕реЗ рдЙрддреНрддрд░реЛрдВ рдХрд╛ рдЕрдзреНрдпрдпрди рдХрд┐рдпрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рд╕рднреА рдирд┐рд░реНрдгрдп extractTypes рдФрд░ рдХреБрдЫ рдкреНрд░рдХрд╛рд░ рдХреА рднрдпрдВрдХрд░ рд╕рд╛рдЗрдХрд┐рд▓реЛрдВ рдХреЗ рд▓рд┐рдП рдиреАрдЪреЗ рдЖрдП, рдЬреИрд╕реЗ:


 type ValidatedValueType<T extends joi.Schema> = T extends joi.StringSchema ? string : T extends joi.NumberSchema ? number : T extends joi.BooleanSchema ? boolean : T extends joi.ObjectSchema ? ValidatedObjectType<T> : /* ... more schemata ... */ never; 

рдирд┐рд░реНрдгрдп


рддреГрддреАрдп-рдкрдХреНрд╖ рдкреБрд╕реНрддрдХрд╛рд▓рдпреЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВ


рдХреНрдпреЛрдВ рдирд╣реАрдВ? рдЬрдм рдореИрдВрдиреЗ рдЕрдкрдиреЗ рдХрд╛рд░реНрдп рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рд▓реЛрдЧреЛрдВ рд╕реЗ рдкреВрдЫрд╛, рддреЛ рдореБрдЭреЗ рдПрдХ рдЙрддреНрддрд░ рдорд┐рд▓рд╛, рдФрд░ рдмрд╛рдж рдореЗрдВ, рдФрд░ рдпрд╣рд╛рдБ, рдЯрд┐рдкреНрдкрдгрд┐рдпреЛрдВ рдореЗрдВ ( keenondrums рдХреЗ рд▓рд┐рдП рдзрдиреНрдпрд╡рд╛рдж), рдЗрди рдкреБрд╕реНрддрдХрд╛рд▓рдпреЛрдВ рдХреЗ рд▓рд┐рдВрдХ:
https://github.com/typestack/class-validator
https://github.com/typestack/class-transformer


рд╣рд╛рд▓рд╛рдВрдХрд┐, рдЯреАрдПрд╕ рдХреЗ рдХрд╛рдо рдХреЛ рдмреЗрд╣рддрд░ рддрд░реАрдХреЗ рд╕реЗ рд╕рдордЭрдиреЗ рдХреЗ рд▓рд┐рдП, рдЗрд╕реЗ рд╕реНрд╡рдпрдВ рд╕рдордЭрдиреЗ рдХрд╛ рдкреНрд░рдпрд╛рд╕ рдХрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛, рдФрд░ рдЗрд╕ рд╕рдорд╕реНрдпрд╛ рдХреЛ рд╣рд▓ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХреБрдЫ рднреА рдЖрдЧреНрд░рд╣ рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛ред


рд╕рднреА рдЧреБрдг рдкреНрд░рд╛рдкреНрдд рдХрд░реЗрдВ


рдЪреВрдВрдХрд┐ рдореБрдЭреЗ рд╕реНрдЯреИрдЯрд┐рдХреНрд╕ рдХреЗ рд╕рд╛рде рдХреЛрдИ рдкрд┐рдЫрд▓рд╛ рдХрд╛рдо рдирд╣реАрдВ рдерд╛, рдЗрд╕рд▓рд┐рдП рдЙрдкрд░реЛрдХреНрдд рдХреЛрдб рдиреЗ рдЕрдореЗрд░рд┐рдХрд╛ рдХреЛ рдЯрд░реНрдирд░реА рдСрдкрд░реЗрдЯрд░реЛрдВ рдХреЗ рдкреНрд░рдХрд╛рд░реЛрдВ рдХреЗ рдЙрдкрдпреЛрдЧ рдХреЗ рд╕рдВрджрд░реНрдн рдореЗрдВ рдЦреЛрдЬрд╛ред рд╕реМрднрд╛рдЧреНрдп рд╕реЗ, рдкрд░рд┐рдпреЛрдЬрдирд╛ рдореЗрдВ рдЗрд╕реЗ рд▓рд╛рдЧреВ рдХрд░рдирд╛ рд╕рдВрднрд╡ рдирд╣реАрдВ рдерд╛ред рд▓реЗрдХрд┐рди рдореБрдЭреЗ рдПрдХ рдФрд░ рджрд┐рд▓рдЪрд╕реНрдк рдмрд╛рдЗрдХ рдорд┐рд▓реА:


 interface IUser { name: string; age: number; phone: string | number; } type UserKeys<T> = { [key in keyof T]; } const evan: UserKeys<IUser> = { name: 'Evan', age: 32, phone: 791234567890 }; const joiUser: UserKeys<IUser> = { name: Joi.string(), age: Joi.number(), phone: Joi.alternatives([Joi.string(), Joi.number()]) }; 

TypeScript рдмрд▓реНрдХрд┐ рдореБрд╢реНрдХрд┐рд▓ рдФрд░ рд░рд╣рд╕реНрдпрдордп рдкрд░рд┐рд╕реНрдерд┐рддрд┐рдпреЛрдВ рдореЗрдВ, рдЖрдкрдХреЛ рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рд╕реЗ рдХреБрдВрдЬрд┐рдпреЛрдВ рдХреЛ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИ, рдЬреИрд╕реЗ рдХрд┐ рдпрд╣ рдПрдХ рд╕рд╛рдорд╛рдиреНрдп рдЬреЗрдПрд╕ рдСрдмреНрдЬреЗрдХреНрдЯ рдерд╛, рд╣рд╛рд▓рд╛рдВрдХрд┐, рдХреЗрд╡рд▓ type рдирд┐рд░реНрдорд╛рдг рдореЗрдВ рдФрд░ key in keyof T рдорд╛рдзреНрдпрдо рд╕реЗ рдФрд░ рдХреЗрд╡рд▓ рдЬреЗрдирд░рд┐рдХ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗред UserKeys рдкреНрд░рдХрд╛рд░ рдХреЗ рдкрд░рд┐рдгрд╛рдорд╕реНрд╡рд░реВрдк, рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдХреЛ рд▓рд╛рдЧреВ рдХрд░рдиреЗ рд╡рд╛рд▓реА рд╕рднреА рд╡рд╕реНрддреБрдУрдВ рдореЗрдВ рдЧреБрдгреЛрдВ рдХрд╛ рд╕рдорд╛рди рд╕реЗрдЯ рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдП, рд▓реЗрдХрд┐рди рдорд╛рдиреЛрдВ рдХреЗ рдкреНрд░рдХрд╛рд░ рдордирдорд╛рдиреЗ рдврдВрдЧ рд╕реЗ рд╣реЛ рд╕рдХрддреЗ рд╣реИрдВред рдЗрд╕рдореЗрдВ рдЖрдИрдбреАрдИ рдореЗрдВ рд╕рдВрдХреЗрдд рд╢рд╛рдорд┐рд▓ рд╣реИрдВ, рд▓реЗрдХрд┐рди рдлрд┐рд░ рднреА рдореВрд▓реНрдпреЛрдВ рдХреЗ рдкреНрд░рдХрд╛рд░реЛрдВ рдХрд╛ рд╕реНрдкрд╖реНрдЯ рд╕рдВрдХреЗрдд рдирд╣реАрдВ рджреЗрддрд╛ рд╣реИред


рдпрд╣рд╛рдВ рдПрдХ рдФрд░ рджрд┐рд▓рдЪрд╕реНрдк рдорд╛рдорд▓рд╛ рд╣реИ рдЬрд┐рд╕рдХрд╛ рдореИрдВ рдЙрдкрдпреЛрдЧ рдирд╣реАрдВ рдХрд░ рд╕рдХрд╛ред рд╢рд╛рдпрдж рдЖрдк рдореБрдЭреЗ рдмрддрд╛ рд╕рдХрддреЗ рд╣реИрдВ рдХрд┐ рдпрд╣ рдХреНрдпреЛрдВ рдЖрд╡рд╢реНрдпрдХ рд╣реИ (рд╣рд╛рд▓рд╛рдВрдХрд┐ рдореИрдВ рдЖрдВрд╢рд┐рдХ рд░реВрдк рд╕реЗ рдЕрдиреБрдорд╛рди рд▓рдЧрд╛рддрд╛ рд╣реВрдВ, рдкрд░реНрдпрд╛рдкреНрдд рд▓рд╛рдЧреВ рдЙрджрд╛рд╣рд░рдг рдирд╣реАрдВ рд╣реИ):


 interface IUser { name: string; age: number; phone: string | number; } interface IUserJoi { name: Joi.StringSchema, age: Joi.NumberSchema, phone: Joi.AlternativesSchema } type UserKeys<T> = { [key in keyof T]: T[key]; } const evan: UserKeys<IUser> = { name: 'Evan', age: 32, phone: 791234567890 }; const userJoiValidator: UserKeys<IUserJoi> = { name: Joi.string(), age: Joi.number(), phone: Joi.alternatives([Joi.string(), Joi.number()]) }; 

рдкрд░рд┐рд╡рд░реНрддрдирд╢реАрд▓ рдкреНрд░рдХрд╛рд░реЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВ


рдЖрдк рд╕реНрдкрд╖реНрдЯ рд░реВрдк рд╕реЗ рдкреНрд░рдХрд╛рд░ рд╕реЗрдЯ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рдФрд░ "OR" рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдФрд░ рдЧреБрдгреЛрдВ рдХреЛ рдирд┐рдХрд╛рд▓ рд╕рдХрддреЗ рд╣реИрдВ, рд╕реНрдерд╛рдиреАрдп рд░реВрдк рд╕реЗ рдХрд╛рдо рдХрд░ рд░рд╣реЗ рдХреЛрдб рдкреНрд░рд╛рдкреНрдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ:


 type TString = string | Joi.StringSchema; type TNumber = number | Joi.NumberSchema; type TStdAlter = TString | TNumber; type TAlter = TStdAlter | Joi.AlternativesSchema; export interface IUser { name: TString; age: TNumber; phone: TAlter; } type UserKeys<T> = { [key in keyof T]; } const olex: UserKeys<IUser> = { name: 'Olex', age: 67, phone: '79998887766' }; const joiUser: UserKeys<IUser> = { name: Joi.string(), age: Joi.number(), phone: Joi.alternatives([Joi.string(), Joi.number()]) }; 

рдЗрд╕ рдХреЛрдб рдХреА рд╕рдорд╕реНрдпрд╛ рддрдм рдкреНрд░рдХрдЯ рд╣реЛрддреА рд╣реИ рдЬрдм рд╣рдо рдХрд┐рд╕реА рдорд╛рдиреНрдп рдСрдмреНрдЬреЗрдХреНрдЯ рдХреЛ рдЪреБрдирдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ, рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдбреЗрдЯрд╛рдмреЗрд╕ рд╕реЗ, рдЕрд░реНрдерд╛рдд, TS рдХреЛ рдкрд╣рд▓реЗ рд╕реЗ рдкрддрд╛ рдирд╣реАрдВ рд╣реИ рдХрд┐ рдбреЗрдЯрд╛ рдХрд┐рд╕ рдкреНрд░рдХрд╛рд░ рдХрд╛ рд╣реЛрдЧрд╛ - рд╕рд░рд▓ рдпрд╛ рдЬреЛрдИред рдЬрдм number рд░реВрдк рдореЗрдВ рдЕрдкреЗрдХреНрд╖рд┐рдд рдлрд╝реАрд▓реНрдб рдкрд░ рдЧрдгрд┐рддреАрдп рдХрд╛рд░реНрдп рдХрд░рдиреЗ рдХрд╛ рдкреНрд░рдпрд╛рд╕ рдХрд░рддреЗ рд╕рдордп рдпрд╣ рддреНрд░реБрдЯрд┐ рд╣реЛ рд╕рдХрддреА рд╣реИ:


 const someUser: IUser = getUserFromDB({ name: 'Aleg' }); const someWeirdMath = someUser.age % 10; // error TS2362: The left-hand side of an arithmetic operation must be of type'any', 'number', 'bigint' or an enum type 

рдпрд╣ рддреНрд░реБрдЯрд┐ Joi.NumberSchema рд╕реЗ рдЖрддреА рд╣реИ рдХреНрдпреЛрдВрдХрд┐ рдЙрдореНрд░ рдХреЗрд╡рд▓ number рдирд╣реАрдВ рд╣реЛ рд╕рдХрддреА рд╣реИред рд╡реЗ рдХрд┐рд╕ рд▓рд┐рдП рд▓рдбрд╝реЗ рдФрд░ рднрд╛рдЧреЗред


рдПрдХ рдореЗрдВ рджреЛ рд╕рдорд╛рдзрд╛рди рдорд┐рд▓рд╛рдПрдВ?


рдЗрд╕ рдмрд┐рдВрджреБ рдкрд░ рдХрд╣реАрдВ, рдХрд╛рд░реНрдп рджрд┐рд╡рд╕ рдЕрдкрдиреЗ рддрд╛рд░реНрдХрд┐рдХ рдирд┐рд╖реНрдХрд░реНрд╖ рдХреЗ рдХрд░реАрдм рдкрд╣реБрдВрдЪ рд░рд╣рд╛ рдерд╛ред рдореИрдВрдиреЗ рдПрдХ рд╕рд╛рдВрд╕ рд▓реА, рдХреЙрдлреА рдкреА рд▓реА рдФрд░ рдХрдордмрдЦреНрдд рдЪреБрджрд╛рдИ рдХреЛ рдорд┐рдЯрд╛ рджрд┐рдпрд╛ред рдпрд╣ рдЖрдкрдХреЗ рдЗрдВрдЯрд░рдиреЗрдЯ рдХреЛ рдХрдо рдкрдврд╝рдиреЗ рдХреЗ рд▓рд┐рдП рдЖрд╡рд╢реНрдпрдХ рд╣реИ! рд╕рдордп рдЖ рдЧрдпрд╛ рдПрдХ рдмрдиреНрджреВрдХ рд▓реЗ рд▓реЛ рдФрд░ poraskinut рджрд┐рдорд╛рдЧ:


  1. рдПрдХ рд╡рд╕реНрддреБ рдХреЛ рд╕реНрдкрд╖реНрдЯ рдореВрд▓реНрдп рдкреНрд░рдХрд╛рд░реЛрдВ рдХреЗ рд╕рд╛рде рдмрдирд╛рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдП;
  2. рдЖрдк рдПрдХрд▓ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдореЗрдВ рдкреНрд░рдХрд╛рд░ рдлреЗрдВрдХрдиреЗ рдХреЗ рд▓рд┐рдП рдЬреЗрдирд░рд┐рдХ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ;
  3. рд╕рд╛рдорд╛рдиреНрдп рд╕рдорд░реНрдерди рдбрд┐рдлрд╝реЙрд▓реНрдЯ рдкреНрд░рдХрд╛рд░;
  4. type рдирд┐рд░реНрдорд╛рдг рд╕реНрдкрд╖реНрдЯ рд░реВрдк рд╕реЗ рдХреБрдЫ рдФрд░ рдХрд░рдиреЗ рдореЗрдВ рд╕рдХреНрд╖рдо рд╣реИред

рд╣рдо рд╕рд╛рдорд╛рдиреНрдп рдкреНрд░рдХрд╛рд░ рдХреЗ рд╕рд╛рде рд╕рд╛рдорд╛рдиреНрдп рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рд▓рд┐рдЦрддреЗ рд╣реИрдВ:


 interface IUser < TName = string, TAge = number, TAlt = string | number > { name: TName; age: TAge; phone: TAlt; } 

рдЬреЛрдИ рдХреЗ рд▓рд┐рдП, рдЖрдк рдПрдХ рджреВрд╕рд░рд╛ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдмрдирд╛ рд╕рдХрддреЗ рд╣реИрдВ, рдЬреЛ рдЗрд╕ рддрд░рд╣ рд╕реЗ рдореБрдЦреНрдп рд╣реИ:


 interface IUserJoi extends IUser < Joi.StringSchema, Joi.NumberSchema, Joi.AlternativesSchema > {} 

рдкрд░реНрдпрд╛рдкреНрдд рдЕрдЪреНрдЫрд╛ рдирд╣реАрдВ рд╣реИ, рдХреНрдпреЛрдВрдХрд┐ рдЕрдЧрд▓реЗ рдбреЗрд╡рд▓рдкрд░ рд╣рд▓реНрдХреЗ рджрд┐рд▓ рдпрд╛ рдмрджрддрд░ рдХреЗ рд╕рд╛рде IUserJoi рд╡рд┐рд╕реНрддрд╛рд░ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рд╕рдорд╛рди рд╡реНрдпрд╡рд╣рд╛рд░ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдЕрдзрд┐рдХ рд╕реАрдорд┐рдд рд╡рд┐рдХрд▓реНрдк рд╣реИ:


 type IUserJoi = IUser<Joi.StringSchema, Joi.NumberSchema, Joi.AlternativesSchema>; 

рд╣рдо рдХреЛрд╢рд┐рд╢ рдХрд░рддреЗ рд╣реИрдВ:


 const aleg: IUser = { name: 'Aleg', age: 45, phone: '79001231212' }; const joiUser: IUserJoi = { name: Joi.string(), age: Joi.number(), phone: Joi.alternatives([Joi.string(), Joi.number()]) }; 

рдпреБрдкреАрдбреА:
Joi.object рдореЗрдВ рд░реИрдк рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП Joi.object рдореБрдЭреЗ Joi.object рд╕реЗ рд▓рдбрд╝рдирд╛ рдкрдбрд╝рд╛ рдФрд░ рд╕рдмрд╕реЗ рд╕рд░рд▓ рдЙрдкрд╛рдп рдпрд╣реА рдерд╛ред рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдпрд╣ рдПрдХ рдорд╣рддреНрд╡рдкреВрд░реНрдг рдзрд╛рд░рдгрд╛ рдирд╣реАрдВ рд╣реИ, рдХреНрдпреЛрдВрдХрд┐ рдЙрдкрд░реЛрдХреНрдд рд╡рд╕реНрддреБ рдЕрднреА рднреА рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдкрд░ рд╣реИред


 const joiUserInfo = { info: Joi.object(joiUser as any).required() }; 

рдпрд╣ рд╕рдВрдХрд▓рди рдХрд░рддрд╛ рд╣реИ, рдЙрдкрдпреЛрдЧ рдХреА рдЬрдЧрд╣ рдкрд░ рд╕рд╛рдл-рд╕реБрдерд░рд╛ рджрд┐рдЦрддрд╛ рд╣реИ, рдФрд░ рд╡рд┐рд╢реЗрд╖ рдкрд░рд┐рд╕реНрдерд┐рддрд┐рдпреЛрдВ рдХреЗ рдЕрднрд╛рд╡ рдореЗрдВ рд╣рдореЗрд╢рд╛ рдбрд┐рдлрд╝реЙрд▓реНрдЯ рдкреНрд░рдХрд╛рд░ рд╕реЗрдЯ рдХрд░рддрд╛ рд╣реИ! рд╕реМрдВрджрд░реНрдп ...
-
... рдореИрдВрдиреЗ рджреЛ рдХрд╛рд░реНрдпрджрд┐рд╡рд╕ рдХреНрдпрд╛ рдмрд┐рддрд╛рдП


рд╕рд╛рд░рд╛рдВрд╢


рдЗрд╕ рд╕рдм рд╕реЗ рдХреНрдпрд╛ рдирд┐рд╖реНрдХрд░реНрд╖ рдирд┐рдХрд╛рд▓рд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ:


  1. рдЬрд╛рд╣рд┐рд░ рд╣реИ, рдореИрдВрдиреЗ рдпрд╣ рдирд╣реАрдВ рд╕реАрдЦрд╛ рдХрд┐ рдкреНрд░рд╢реНрдиреЛрдВ рдХреЗ рдЙрддреНрддрд░ рдХреИрд╕реЗ рдЦреЛрдЬреЗ рдЬрд╛рдПрдБред рдирд┐рд╢реНрдЪрд┐рдд рд░реВрдк рд╕реЗ, рдПрдХ рд╕рдлрд▓ рдЕрдиреБрд░реЛрдз рдХреЗ рд╕рд╛рде, рдпрд╣ рд╕рдорд╛рдзрд╛рди (рдпрд╛ рдЗрд╕рд╕реЗ рднреА рдмреЗрд╣рддрд░) рдЦреЛрдЬ рдЗрдВрдЬрди рдХреЗ рдкрд╣рд▓реЗ 5k рд▓рд┐рдВрдХ рдореЗрдВ рд╣реИ;
  2. рдЧрддрд┐рд╢реАрд▓ рд╕реЗ рд╕реНрдерд┐рд░ рд╕реЛрдЪ рдкрд░ рд╕реНрд╡рд┐рдЪ рдХрд░рдирд╛ рдЗрддрдирд╛ рдЖрд╕рд╛рди рдирд╣реАрдВ рд╣реИ, рдмрд╣реБрдд рдмрд╛рд░ рдореИрдВ рдРрд╕реЗ рдЭреБрдВрдб рдкрд░ рд╕рд┐рд░реНрдл рд╣рдереМрдбрд╝рд╛ рдЪрд▓рд╛рддрд╛ рд╣реВрдВ;
  3. рдЬреЗрдирд░рд┐рдХ рд╢рд╛рдВрдд рд╣реИрдВред рд╣реЗрдмреНрд░рд╛ рдФрд░ рд╕реНрдЯреИрдХрдУрд╡рд░рдлрд╝реНрд▓реЛ рдкрд░ рднрд░рд╛ рд╣реБрдЖ рд╣реИ рд╕рд╛рдЗрдХрд┐рд▓реЛрдВ рдХреА рдЧреИрд░-рд╕реНрдкрд╖реНрдЯ рд╕рдорд╛рдзрд╛рди рдордЬрдмреВрдд рдЯрд╛рдЗрдкрд┐рдВрдЧ рдХреЗ рдирд┐рд░реНрдорд╛рдг рдХреЗ рд▓рд┐рдП ... рд░рдирдЯрд╛рдЗрдо рдХреЗ рдмрд╛рд╣рд░ред

рд╣рдордиреЗ рдХреНрдпрд╛ рдЬреАрддрд╛:


  1. рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдмрджрд▓рддреЗ рд╕рдордп, рд╕рднреА рдХреЛрдб рдмрдВрдж рд╣реЛ рдЬрд╛рддрд╛ рд╣реИ, рдЬрд┐рд╕рдореЗрдВ рд╕рддреНрдпрд╛рдкрдирдХрд░реНрддрд╛ рднреА рд╢рд╛рдорд┐рд▓ рд╣реИ;
  2. рд╕рдВрдкрд╛рджрдХ рдореЗрдВ, рд╕рдВрдкрддреНрддрд┐ рдХреЗ рдирд╛рдо рдФрд░ рд╡реИрдзрддрд╛ рд▓рд┐рдЦрдиреЗ рдХреЗ рд▓рд┐рдП рдСрдмреНрдЬреЗрдХреНрдЯ рд╡реИрд▓реНрдпреВ рдХреЗ рдкреНрд░рдХрд╛рд░реЛрдВ рдкрд░ рд╕реБрдЭрд╛рд╡ рджрд┐рдЦрд╛рдИ рджрд┐рдП;
  3. рдПрдХ рд╣реА рдЙрджреНрджреЗрд╢реНрдп рдХреЗ рд▓рд┐рдП рдЕрд╕реНрдкрд╖реНрдЯ рддреГрддреАрдп-рдкрдХреНрд╖ рдкреБрд╕реНрддрдХрд╛рд▓рдпреЛрдВ рдХреА рдХрдореА;
  4. рдЬреЙрдп рдирд┐рдпрдореЛрдВ рдХреЛ рдХреЗрд╡рд▓ рд╡рд╣реАрдВ рд▓рд╛рдЧреВ рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ рдЬрд╣рд╛рдВ рдЖрд╡рд╢реНрдпрдХ рд╣реЛ, рдЕрдиреНрдп рдорд╛рдорд▓реЛрдВ рдореЗрдВ, рдбрд┐рдлрд╝реЙрд▓реНрдЯ рдкреНрд░рдХрд╛рд░;
  5. рдпрджрд┐ рдХреЛрдИ рдХрд┐рд╕реА рд╕рдВрдкрддреНрддрд┐ рдХреЗ рдореВрд▓реНрдп рдХреЗ рдкреНрд░рдХрд╛рд░ рдХреЛ рдмрджрд▓рдирд╛ рдЪрд╛рд╣рддрд╛ рд╣реИ, рддреЛ рдХреЛрдб рдХреЗ рд╕рд╣реА рд╕рдВрдЧрдарди рдХреЗ рд╕рд╛рде, рд╡рд╣ рдЙрд╕ рд╕реНрдерд╛рди рдкрд░ рдЧрд┐рд░ рдЬрд╛рдПрдЧрд╛ рдЬрд╣рд╛рдВ рдЗрд╕ рд╕рдВрдкрддреНрддрд┐ рд╕реЗ рдЬреБрдбрд╝реЗ рд╕рднреА рдкреНрд░рдХрд╛рд░ рдПрдХ рд╕рд╛рде рдЗрдХрдЯреНрдард╛ рд╣реЛрддреЗ рд╣реИрдВ;
  6. рд╣рдордиреЗ рдЦреВрдмрд╕реВрд░рддреА рд╕реЗ рд╕реАрдЦрд╛ рд╣реИ рдФрд░ рдмрд╕ type рдЕрдореВрд░реНрдд рдХреЗ рдкреАрдЫреЗ рдЬреЗрдиреЗрд░рд┐рдХ рдЫрд┐рдкрд╛рддреЗ рд╣реИрдВ, рдиреЗрддреНрд░рд╣реАрди рд░рд╛рдХреНрд╖рд╕реА рдирд┐рд░реНрдорд╛рдгреЛрдВ рд╕реЗ рдХреЛрдб рдХреЛ рдЕрдирд▓реЛрдб рдХрд░рддреЗ рд╣реИрдВред

рдиреИрддрд┐рдХ: рдЕрдиреБрднрд╡ рдЕрдирдореЛрд▓ рд╣реИ, рдмрд╛рдХреА рдХреЗ рд▓рд┐рдП, рдПрдХ рд╡рд┐рд╢реНрд╡ рдорд╛рдирдЪрд┐рддреНрд░ рд╣реИред


рдЖрдк рдЕрдВрддрд┐рдо рдкрд░рд┐рдгрд╛рдо рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВ, рдЫреВ рд╕рдХрддреЗ рд╣реИрдВ, рднрд╛рдЧ рд╕рдХрддреЗ рд╣реИрдВ:
https://repl.it/@Melodyn/Joi-by-interface

Source: https://habr.com/ru/post/hi450238/


All Articles