рдЯрд╛рдЗрдкрд╕реНрдХреНрд░рд┐рдкреНрдЯ рдФрд░ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛-рд╣реБрдХ рдХреЗ рд▓рд┐рдП рдЬреВрдирд┐рдпрд░ рдлреНрд░рдВрдЯ рдХреЗ рд▓рд┐рдП рдкрд░реАрдХреНрд╖рдг рдорд╛рдорд▓реЗ рдХреЛ рдлрд┐рд░ рд╕реЗ рд▓рд┐рдЦрдирд╛

рд╣рд╛рдп рд╣рдмрд░, рдЖрдЬ рд╣рдо рдЯрд╛рдЗрдкрд╕реНрдХреНрд░рд┐рдкреНрдЯ рдФрд░ рд░рд┐рдПрдХреНрдЯ-рд╣реБрдХ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░реЗрдВрдЧреЗред рдпрд╣ рдЯреНрдпреВрдЯреЛрд░рд┐рдпрд▓ рдЖрдкрдХреЛ "рд╕реНрдХреНрд░рд┐рдкреНрдЯ" рдХреА рдореВрд▓ рдмрд╛рддреЗрдВ рд╕рдордЭрдиреЗ рдореЗрдВ рдорджрдж рдХрд░реЗрдЧрд╛ рдФрд░ рдлреНрд░рдВрдЯ-рдПрдВрдб рдХреЗ рд▓рд┐рдП рдПрдХ рдкрд░реАрдХреНрд╖рдг рдХрд╛рд░реНрдп рдкрд░ рдХрд╛рдо рдХрд░рдиреЗ рдореЗрдВ рдорджрдж рдХрд░реЗрдЧрд╛ред


рдкреНрд░реЛрдЬреЗрдХреНрдЯ "рд╡рд┐рджрд╛рдЙрдЯ рд╡реЙрдЯрд░" рдкрд░ рдкрд░реАрдХреНрд╖рдг рдХрд╛рд░реНрдп рдХреЛрдб-рд╕рдореАрдХреНрд╖рд╛ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХрд╛ рдПрдХ рдЕрд╡рд╕рд░ рд╣реИред рд╡рд░реНрддрдорд╛рди рдЕрд╕рд╛рдЗрдирдореЗрдВрдЯ рдХреА рдЕрдВрддрд┐рдо рддрд┐рдерд┐ 11 рдЕрдкреНрд░реИрд▓, 2019 рд╣реИред



рд╡реАрдбрд┐рдпреЛ рд╕рдВрд╕реНрдХрд░рдг


рдпрджрд┐ рдЖрдк рдкрдврд╝рдиреЗ рдореЗрдВ рдмрд╣реБрдд рдЖрд▓рд╕реА рд╣реИрдВ, рддреЛ 20 рдорд╛рд░реНрдЪ рдХреЛ 21:00 рдорд╛рд╕реНрдХреЛ рд╕рдордп рдкрд░ рд╡реЗрдмрд┐рдирд╛рд░ рдореЗрдВ рдЖрдПрдВред рдкрдВрдЬреАрдХрд░рдг (рдИ-рдореЗрд▓ рдФрд░ рдПрд╕рдПрдордПрд╕ рдХреЗ рдмрд┐рдирд╛)ред рд╡реЗрдмрд┐рдирд╛рд░ рдЖрдпреЛрдЬрд┐рдд, рд╡реЗрдмрд┐рдирд╛рд░ рд░рд┐рдХреЙрд░реНрдбрд┐рдВрдЧ ред


рдЯреНрд░реЗрдирд┐рдВрдЧ


рд╢реБрд░реВ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдЖрдк Create-react-app рдЯрд╛рдЗрдкрд╕реНрдХреНрд░рд┐рдкреНрдЯ рд╕рдВрд╕реНрдХрд░рдг рд▓реЗ рд╕рдХрддреЗ рд╣реИрдВ, рдпрд╛ рдореЗрд░реЗ рд╕реНрдЯрд╛рд░реНрдЯрд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ (рдЬрд┐рд╕рдореЗрдВ рдкрд╣рд▓реЗ рд╕реЗ рдкрд╣реБрдВрдЪ-рд░рд╛рдЙрдЯрд░ рд╢рд╛рдорд┐рд▓ рд╣реИрдВ)


рдореИрдВ рдЕрдкрдиреЗ рд╕реНрдЯрд╛рд░реНрдЯрд░ ("рдЕрднреНрдпрд╛рд╕" рдЕрдиреБрднрд╛рдЧ рдореЗрдВ рдЗрд╕рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЕрдзрд┐рдХ) рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реВрдВрдЧрд╛ ред


рдЯрд╛рдЗрдкрд╕реНрдХреНрд░рд┐рдкреНрдЯ рдереНрдпреЛрд░реА


рдЯреАрдПрд╕ рдЬрд╛рд╡рд╛рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдореЗрдВ "рдЧрддрд┐рд╢реАрд▓ рдЯрд╛рдЗрдкрд┐рдВрдЧ" рдХреА рд╕рдорд╕реНрдпрд╛ рдХреЛ рд╣рд▓ рдХрд░рддрд╛ рд╣реИ, рдЬрдм рдЖрдкрдХрд╛ рдЪрд░ рдЕрд▓рдЧ-рдЕрд▓рдЧ рдорд╛рди рд▓реЗ рд╕рдХрддрд╛ рд╣реИред рдЕрдм рдПрдХ рд░реЗрдЦрд╛, рдлрд┐рд░ рдПрдХ рд╕рдВрдЦреНрдпрд╛, рдпрд╛ рдПрдХ рд╡рд╕реНрддреБ рднреАред 19 рд╡реАрдВ рд╢рддрд╛рдмреНрджреА рдореЗрдВ рдЗрд╕ рддрд░рд╣ рд╕реЗ рд▓рд┐рдЦрдирд╛ рд╕реБрд╡рд┐рдзрд╛рдЬрдирдХ рдерд╛, рд╣рд╛рд▓рд╛рдВрдХрд┐, рдЕрдм рд╣рд░ рдХреЛрдИ рдЗрд╕ рдмрд╛рдд рд╕реЗ рд╕рд╣рдордд рд╣реИ рдХрд┐ рдпрджрд┐ рдЖрдкрдХреЗ рдкрд╛рд╕ рдкреВрд░реНрд╡рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдкреНрд░рдХрд╛рд░ (рдирд┐рдпрдореЛрдВ рдкрд░ рд╡рд┐рдЪрд╛рд░ рдХрд░реЗрдВ) рд╣реИ, рддреЛ рдХреЛрдб рдЖрдзрд╛рд░ рдмрдирд╛рдП рд░рдЦрдирд╛ рдЖрд╕рд╛рди рд╣реИред рдФрд░ рд╡рд┐рдХрд╛рд╕ рдХреЗ рд╕реНрддрд░ рдкрд░ рдХрдо рдХреАрдбрд╝реЗ рд╣реИрдВред


рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдпрджрд┐ рдЖрдкрдХреЗ рдкрд╛рд╕ рдПрдХ рдШрдЯрдХ рд╣реИ рдЬреЛ рдПрдХ рд╕рдорд╛рдЪрд╛рд░ рдЖрдЗрдЯрдо рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рддрд╛ рд╣реИ, рддреЛ рд╣рдо рд╕рдорд╛рдЪрд╛рд░ рдЖрдЗрдЯрдо рдХреЗ рд▓рд┐рдП рдирд┐рдореНрди рдкреНрд░рдХрд╛рд░ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ:


//   -   { } // c  export interface INewsItem { id: number; // id  -   title: string; // title () -  text: string; // text ( ) -  link: string; // link () -  timestamp: Date; // timestamp () -    js } 

рдЗрд╕ рдкреНрд░рдХрд╛рд░, рд╣рдордиреЗ рдЕрдкрдиреЗ "рд╕рдорд╛рдЪрд╛рд░" рдСрдмреНрдЬреЗрдХреНрдЯ рдХреЗ рдЧреБрдгреЛрдВ рдХреЗ рд▓рд┐рдП рд╕рдЦреНрдд "рд╕реНрдерд┐рд░" рдкреНрд░рдХрд╛рд░ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд┐рдП рд╣реИрдВред рдЕрдЧрд░ рд╣рдо рдПрдХ рднреАрдордХрд╛рдп рд╕рдВрдкрддреНрддрд┐ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рдЯрд╛рдЗрдкрд╕реНрдХреНрд░рд┐рдкреНрдЯ рдПрдХ рддреНрд░реБрдЯрд┐ рджрд┐рдЦрд╛рдПрдЧрд╛ред


 import * as React from 'react' import { INewsItem } from '../models/news' //  "" interface INewsItemProps { data: INewsItem; //  ,   (    ) } const NewsItem: React.FC<INewsItemProps> = ({ data: { id, text, abracadabra }, //    , id  text - , abracadabra -  }) => { return ( <article> <div>{id}</div> <div>{text}</div> </article> ) } export { NewsItem } 


рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, рд╡рд┐рдЬрд╝реБрдЕрд▓ рд╕реНрдЯреВрдбрд┐рдпреЛ рдХреЛрдб рдФрд░ рдЕрдиреНрдп рдЙрдиреНрдирдд рд╕рдВрдкрд╛рджрдХ рдЖрдкрдХреЛ рдПрдХ рддреНрд░реБрдЯрд┐ рджрд┐рдЦрд╛рдПрдВрдЧреЗ:



рджреГрд╖реНрдЯрд┐рдЧрдд, рд╕реБрд╡рд┐рдзрд╛рдЬрдирдХред рдореЗрд░реЗ рдорд╛рдорд▓реЗ рдореЗрдВ, рд╡реАрдПрд╕ рдХреЛрдб рджреЛ рддреНрд░реБрдЯрд┐рдпреЛрдВ рдХреЛ рдПрдХ рд╕рд╛рде рджрд┐рдЦрд╛рддрд╛ рд╣реИ: рдЪрд░ рдХрд╛ рдкреНрд░рдХрд╛рд░ рд╕реЗрдЯ рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ (рдЕрд░реНрдерд╛рдд, рдпрд╣ рд╣рдорд╛рд░реЗ "рдЗрдВрдЯрд░рдлрд╝реЗрд╕" рд╕рдорд╛рдЪрд╛рд░ рдореЗрдВ рдореМрдЬреВрдж рдирд╣реАрдВ рд╣реИ) рдФрд░ "рдЪрд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИред" рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, рдЕрдкреНрд░рдпреБрдХреНрдд рдЪрд░ рдЬрдм рдЯрд╛рдЗрдкрд╕реНрдХреНрд░рд┐рдкреНрдЯ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВ рддреЛ рдбрд┐рдлрд╝реЙрд▓реНрдЯ рд░реВрдк рд╕реЗ рд╡реАрдПрд╕ рдХреЛрдб рдореЗрдВ рд╣рд▓реНрдХреЗ рд░рдВрдЧ рдореЗрдВ рд╣рд╛рдЗрд▓рд╛рдЗрдЯ рдХрд┐рдП рдЬрд╛рддреЗ рд╣реИрдВред


рдпрд╣рд╛рдВ рдПрдХ рдкрдВрдХреНрддрд┐ рдореЗрдВ рдпрд╣ рдЗрдВрдЧрд┐рдд рдХрд░рдирд╛ рд╕рд╛рд░реНрдердХ рд╣реИ рдХрд┐ рдЯрд╛рдЗрдкрд╕реНрдХреНрд░рд┐рдкреНрдЯ рдФрд░ рд╡реАрдПрд╕ рдХреЛрдб рдХреЗ рдРрд╕реЗ рдШрдирд┐рд╖реНрда рдПрдХреАрдХрд░рдг рдХрд╛ рдХрд╛рд░рдг: рджреЛрдиреЛрдВ рдЙрддреНрдкрд╛рдж Microsoft рдХреЗ рд╡рд┐рдХрд╛рд╕ рд╣реИрдВред


рдЯрд╛рдЗрдкрд╕реНрдХреНрд░рд┐рдкреНрдЯ рд╣рдореЗрдВ рдФрд░ рдХреНрдпрд╛ рдмрддрд╛ рд╕рдХрддрд╛ рд╣реИ? рдЪрд░ рдХреЗ рд╕рдВрджрд░реНрдн рдореЗрдВ рдмреЛрд▓рддреЗ рд╣реБрдП, рдпрд╣ рдмрд╛рдд рд╣реИред рдЯреАрдПрд╕ рдмрд╣реБрдд рд╢рдХреНрддрд┐рд╢рд╛рд▓реА рд╣реИ, рд╡рд╣ рд╕рдордЭрддрд╛ рд╣реИ рдХрд┐ рдХреНрдпрд╛ рд╣реИред


 const NewsItem: React.FC<INewsItemProps> = ({ data: { id, title, text } }) => { return ( <article> <div>{id.toUpperCase()}</div> {/* , ,  'number'   toUpperCase() */} <div>{title.toUpperCase()}</div> {/*    ! */} <div>{text}</div> </article> ) } 


рдпрд╣рд╛рдБ, рдЯрд╛рдЗрдкрд╕реНрдХреНрд░рд┐рдкреНрдЯ рддреБрд░рдВрдд рдПрдХ number рдХреА рд╕рдВрдкрддреНрддрд┐ рдкрд░ рд╢рдкрде рд▓реЗрддрд╛ рд╣реИ - рдЯрд╛рдЗрдк number рдХрд╛ рдЯреЙрдкрд░рдХреЗрд╕ред рдФрд░ рдЬреИрд╕рд╛ рдХрд┐ рд╣рдо рдЬрд╛рдирддреЗ рд╣реИрдВ, рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ, рдХреЗрд╡рд▓ рд╕реНрдЯреНрд░рд┐рдВрдЧ рдкреНрд░рдХрд╛рд░реЛрдВ рдореЗрдВ рдЯреЙрдкрд░ рдХреИрд╕ () рд╡рд┐рдзрд┐рдпрд╛рдВ рд╣реИрдВред


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


рдпрд╛ рдХрд▓реНрдкрдирд╛ рдХрд░реЗрдВ - рдЖрдкрдиреЗ рдХрдбрд╝рд╛рдИ рд╕реЗ рд╕рд┐рдлрд╛рд░рд┐рд╢реЛрдВ рдХрд╛ рдкрд╛рд▓рди рдХрд┐рдпрд╛ рдФрд░ рдЖрдкрдХреЗ рдкреНрд░реЛрдЬреЗрдХреНрдЯ рдкрд░ рдЯрд╛рдЗрдк рдХрд░рдирд╛ рдмреБрд▓реЗрдЯрдкреНрд░реВрдл рд╣реИред рдСрдЯреЛ-рдкреНрд░рддрд┐рд╕реНрдерд╛рдкрди рдХреЗ рдЕрд▓рд╛рд╡рд╛, рдЖрдкрдХреЛ рдкрд░рд┐рдпреЛрдЬрдирд╛ рдкрд░ рдирд┐рд╣рд┐рдд ( undefined ) рдореВрд▓реНрдпреЛрдВ рдХреЗ рд╕рд╛рде рд╕рдорд╕реНрдпрд╛ рд╕реЗ рдЫреБрдЯрдХрд╛рд░рд╛ рдорд┐рд▓рддрд╛ рд╣реИред


рдЕрднреНрдпрд╛рд╕


рд╣рдо рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛-рд╣реБрдХ + рдЯрд╛рдЗрдкрд╕реНрдХреНрд░рд┐рдкреНрдЯ рдкрд░ рдкрд╣рд▓реЗ рдкрд░реАрдХреНрд╖рдг рдХрд╛рд░реНрдп рдХреЛ рдлрд┐рд░ рд╕реЗ рд▓рд┐рдЦрддреЗ рд╣реИрдВред рдЕрднреА рдХреЗ рд▓рд┐рдП, рдЪрд▓реЛ Redux рдХреЛ рдЫреЛрдбрд╝ рджреЗрдВ, рдЕрдиреНрдпрдерд╛ " рдкреБрдирд░рд╛рд░рдВрдн рдХрд┐рдП рдЧрдП TK # 1 " рдкрд░ рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рдмрдЬрд╛рдп , рдЖрдк рдмрд╕ рдпрд╣рд╛рдВ рд╕реЗ рд╕рдм рдХреБрдЫ рдХреЙрдкреА рдХрд░рддреЗ рд╣реИрдВред


рдЙрдкрдХрд░рдг


( рд╡реАрдПрд╕ рдХреЛрдб рдХрд╛ рдЗрд╕реНрддреЗрдорд╛рд▓ рдХрд░рдиреЗ рд╡рд╛рд▓реЛрдВ рдХреЗ рд▓рд┐рдП)


рд╕реБрд╡рд┐рдзрд╛ рдХреЗ рд▓рд┐рдП, рдореИрдВ рдЖрдкрдХреЛ TSLint рдПрдХреНрд╕рдЯреЗрдВрд╢рди рд╕реНрдерд╛рдкрд┐рдд рдХрд░рдиреЗ рдХреА рд╕рд▓рд╛рд╣ рджреЗрддрд╛ рд╣реВрдВред


рдмрдЪрдд рдХреЗ рд╕рдордп TSLint рддреНрд░реБрдЯрд┐ рдХреЛ рд╕реНрд╡рддрдГ рдареАрдХ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╕рдВрдкрд╛рджрдХ рд╕реЗрдЯрд┐рдВрдЧ рдореЗрдВ рдЬреЛрдбрд╝реЗрдВ:


 //  settings.json visual studio "editor.codeActionsOnSave": { "source.fixAll.tslint": true } 

рдЖрдк рдореЗрдиреВ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рд╕реЗрдЯрд┐рдВрдЧреНрд╕ рдореЗрдВ рдЬрд╛ рд╕рдХрддреЗ рд╣реИрдВ, рдпрд╛ рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВ рдХрд┐ рд╡реЗ рдЖрдкрдХреЗ рдСрдкрд░реЗрдЯрд┐рдВрдЧ рд╕рд┐рд╕реНрдЯрдо рдореЗрдВ рд╢рд╛рд░реАрд░рд┐рдХ рд░реВрдк рд╕реЗ рдХрд╣рд╛рдВ рд░рд╣рддреЗ рд╣реИрдВ ред


TSLint рд╕реЗрдЯрд┐рдВрдЧреНрд╕ рдорд╛рдирдХ рд╣реИрдВ, рд╕рд╛рде рд╣реА рдореИрдВрдиреЗ рдПрдХ рдирд┐рдпрдо рдХреЛ рдЕрдХреНрд╖рдо рдХрд░ рджрд┐рдпрд╛ рд╣реИред


 { "extends": ["tslint:recommended", "tslint-react", "tslint-config-prettier"], "linterOptions": { "exclude": [ "node_modules/**/*.ts", "src/serviceWorker.js" ] }, "rules": { "object-literal-sort-keys": false //        } } 

рдПрдХреАрдХрд░рдг рдЦрддреНрдо рд╣реЛ рдЧрдпрд╛ рд╣реИ!


рд╣рдо рдПрдХ рдЖрд╡реЗрджрди рд▓рд┐рдЦ рд░рд╣реЗ рд╣реИрдВ


рд╣рдо рдирд╛рдЯрдХ рдХреЗ рджреМрд░рд╛рди рд╣реА рд╣рдорд╛рд░реЗ рд▓рд┐рдП рдирдИ рдЪреАрдЬреЛрдВ рд╕реЗ рдкрд░рд┐рдЪрд┐рдд рд╣реЛ рдЬрд╛рдПрдВрдЧреЗред рдЖрд░рдВрдн рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдЕрдкрдиреА 1-рд╕реНрдЯрд╛рд░реНрдЯ рд╢рд╛рдЦрд╛ рдХреЛ рдХреНрд▓реЛрди рдХрд░реЗрдВ рдпрд╛ рдЕрдкрдиреЗ рдХреЛрдб рдореЗрдВ рдореЗрд░реЗ рдХреЛрдб рдХреЗ рд╕рд╛рде рд╕рд┐рдВрдХреНрд░рдирд╛рдЗрдЬрд╝ рдХрд░реЗрдВред


рд╕рднреА рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдкреНрд░рдХрд╛рд░ рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдлрд╝рд╛рдЗрд▓реЗрдВ рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдПрдХреНрд╕рдЯреЗрдВрд╢рди .tsx рд╣реИ ред


рд╢реБрд░реБрдЖрддреА рдЯреЗрдореНрдкрд▓реЗрдЯ рдореЗрдВ рдХреНрдпрд╛ рджрд┐рд▓рдЪрд╕реНрдк рд╣реИ?


  • рдкреНрд░реА-рдХрдорд┐рдЯ рд╣реБрдХ (рд╣рдордиреЗ рдкрд╣рд▓реЗ рд╣реА рдЗрд╕ рдкрд░ рдЪрд░реНрдЪрд╛ рдХреА: рдкрд╛рда , рд╡реАрдбрд┐рдпреЛ )
  • TSLint ( ESLint рдкреНрд░рддрд┐рд╕реНрдерд╛рдкрди)
  • рдЗрд╕ рдФрд░ рдЕрдЧрд▓реЗ рдХрджрдо рдХреЗ рд▓рд┐рдП рд╢реБрд░реВ рдХрд░рдиреЗ рдФрд░ рдирд┐рд░реНрднрд░рддрд╛ рдХреЗ рд▓рд┐рдП рдлрд╝рд╛рдЗрд▓реЗрдВ

рдЖрдЗрдП src / App.tsx рдХреЗ рд╕рд╛рде рдЖрд░рдВрдн рдХрд░реЗрдВ:


 import * as React from 'react' import './App.css' const App = () => { return ( <div className="container"> <h1>TZ #1 with hooks & TypeScript</h1> <nav> <p></p> </nav> <p> </p> </div> ) } const RoutedApp = () => { return <App /> } export { RoutedApp } 


рдареАрдХ рд╣реИ, рдорд╛рдирдХ рд╢реБрд░реБрдЖрддред рдЖрдЗрдП <App /> рдХреБрдЫ рд╕рдВрдкрддреНрддрд┐ рдЬреЛрдбрд╝рдиреЗ рдХрд╛ рдкреНрд░рдпрд╛рд╕ рдХрд░реЗрдВ


src / App.tsx


 const App = props => { return ( <div className="container"> <h1>TZ #1 with hooks & TypeScript</h1> <nav> <p></p> </nav> <p> </p> {/*   name  props */} <p>, {props.name}</p> </div> ) } //  name const RoutedApp = () => { return <App name="Max Frontend" /> } 

рд╣рдореЗрдВ рддреНрд░реБрдЯрд┐ рдорд┐рд▓рддреА рд╣реИ:



(рдпрджрд┐ рдЖрдкрдХреЛ рддреНрд░реБрдЯрд┐ рдирд╣реАрдВ рдорд┐рд▓реА рд╣реИ, рддреЛ рдЕрдкрдиреА tsconfig.json рд╕реЗрдЯрд┐рдВрдЧреНрд╕ рдХреА рдХрдареЛрд░рддрд╛ рдХреА рдЬрд╛рдВрдЪ рдХрд░реЗрдВ, рдПрдХ noImplicitAny рдирд┐рдпрдо рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдП)


рдЖрдк рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рддреНрд░реБрдЯрд┐ рдкрд╛рда рдХреЗ рдЕрдиреБрд╡рд╛рдж рд╕реЗ рдЕрдиреБрдорд╛рди рд▓рдЧрд╛рддреЗ рд╣реИрдВ рдХрд┐ рд╣рдорд╛рд░реЗ рдЧреБрдг рдХрд┐рд╕реА рднреА рдкреНрд░рдХрд╛рд░ рдХреЗ рдирд╣реАрдВ рд╣реЛрдиреЗ рдЪрд╛рд╣рд┐рдПред рдЗрд╕ рдкреНрд░рдХрд╛рд░ рдХрд╛ рдЕрдиреБрд╡рд╛рдж "рдХреБрдЫ рднреА" рдХреЗ рд░реВрдк рдореЗрдВ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред рд╣рдорд╛рд░реА рдкрд░рд┐рдпреЛрдЬрдирд╛ рдореЗрдВ рдПрдХ рдирд┐рдпрдо рд╣реИ рдЬреЛ рдЗрд╕ рдкреНрд░рдХрд╛рд░ рдХреЗ рдирд┐рд╣рд┐рдд рдЙрддреНрдкрд╛рджрди рдХреЛ рд░реЛрдХрддрд╛ рд╣реИред


- рдирд┐рд╣рд┐рдд рдкреНрд░рдХрд╛рд░ рдХрд╛ рдЕрдиреБрдорд╛рди?


- рдмрд┐рд▓реНрдХреБрд▓! рдЯрд╛рдЗрдкрд╕реНрдХреНрд░рд┐рдкреНрдЯ рдбрд┐рдлрд╝реЙрд▓реНрдЯ рд░реВрдк рд╕реЗ рдПрдХ рдЪрд░ рдХреЗ рдкреНрд░рдХрд╛рд░ рдХреЛ рдХрдо рдХрд░рдиреЗ рдореЗрдВ рд╕рдХреНрд╖рдо рд╣реИ рдФрд░ рдпрд╣ рдЗрд╕ рдХреБрдПрдВ рд╕реЗ рдореБрдХрд╛рдмрд▓рд╛ рдХрд░рддрд╛ рд╣реИред рдЗрд╕реЗ Type Inference рдХрд╣рддреЗ рд╣реИрдВ ред


рдПрдХ рдЙрджрд╛рд╣рд░рдг:


 let x = 3 // TS ,  x   number,   number  " " (implicit) let x: number = 3 //   (explicit) ,  x   number //       , //       TS      

props рдХреЗ рдорд╛рдорд▓реЗ рдореЗрдВ - рдЯреАрдПрд╕ 100% рддрдХ рдЪрд░ рдХреЗ рдкреНрд░рдХрд╛рд░ рдХреЛ рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдирд╣реАрдВ рдХрд░ рд╕рдХрддрд╛ рд╣реИ рдФрд░ рдЗрд╕рд▓рд┐рдП рдХрд╣рддрд╛ рд╣реИ - рдЗрд╕реЗ рд╣реЛрдиреЗ рджреЗрдВ (рдЕрд░реНрдерд╛рдд рдЯрд╛рдЗрдк рдХрд░реЗрдВ)ред рдпрд╣ рдЕрдВрддрд░реНрдирд┐рд╣рд┐рдд рд░реВрдк рд╕реЗ рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ рдФрд░ рдпрд╣ рдкрд░рд┐рдпреЛрдЬрдирд╛ рд╕реЗрдЯрд┐рдВрдЧреНрд╕ (tsconfig.json) рдореЗрдВ noImplicitAny рдирд┐рдпрдо рджреНрд╡рд╛рд░рд╛ рдирд┐рд╖рд┐рджреНрдз рд╣реИред


рд╣рдо рд╕реНрдкрд╖реНрдЯ рд░реВрдк рд╕реЗ рдХрд┐рд╕реА рднреА рдкреНрд░рдХрд╛рд░ рдХреЛ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдФрд░ рддреНрд░реБрдЯрд┐ рдЧрд╛рдпрдм рд╣реЛ рдЬрд╛рдПрдЧреАред рдЪрд░ рдХрд╛ рдкреНрд░рдХрд╛рд░ рдПрдХ рдмреГрд╣рджрд╛рдиреНрддреНрд░ рджреНрд╡рд╛рд░рд╛ рдЗрдВрдЧрд┐рдд рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИред


 //    :any //    "props: any"        //    const App = (props: any) => { return ( <div className="container"> <h1>TZ #1 with hooks & TypeScript</h1> <nav> <p></p> </nav> <p> </p> <p>, {props.name}</p> </div> ) } 

рдХрд┐рдпрд╛, рдХреЛрдИ рддреНрд░реБрдЯрд┐ рдирд╣реАрдВ рд╣реИ, рдкрд░рд┐рдпреЛрдЬрдирд╛ рдХрд╛рдо рдХрд░рддреА рд╣реИ, рд▓реЗрдХрд┐рди рдРрд╕реЗ рдЯрд╛рдЗрдкрд┐рдВрдЧ рдХрд╛ рдХреНрдпрд╛ рдлрд╛рдпрджрд╛ рдЬрдм props рдХреБрдЫ рднреА рд╣реЛ рд╕рдХрддрд╛ рд╣реИ? рд╣рдо рдпрд╣ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЬрд╛рдирддреЗ рд╣реИрдВ рдХрд┐ рд╣рдорд╛рд░рд╛ рдирд╛рдо рдПрдХ ред рдирд┐рдпрдо рдЗрд╕ рдкреНрд░рдХрд╛рд░ рд╣реИ:


рдХрд┐рд╕реА рднреА рдкреНрд░рдХрд╛рд░ рд╕реЗ рдмрдЪрдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХрд░реЗрдВ

рдРрд╕реЗ рд╕рдордп рд╣реЛрддреЗ рд╣реИрдВ рдЬрдм any рдЖрд╡рд╢реНрдпрдХ any рд╣реИ рдФрд░ рдпрд╣ рд╕рд╛рдорд╛рдиреНрдп рд╣реЛрддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рд╕рдЦреНрдд рдЯрд╛рдЗрдкрд┐рдВрдЧ рд╕реЗ рдпрд╣ рдХрдорд░ рд╕реЗ рдиреАрдЪреЗ рдПрдХ рдЭрдЯрдХрд╛ рд╣реИред


props рдкреНрд░рдХрд╛рд░реЛрдВ рдХрд╛ рд╡рд░реНрдгрди рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдо interface рдХреАрд╡рд░реНрдб рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВрдЧреЗ:


 //  ,   IAppProps //    I,      TSLint  //  I     interface IAppProps { name: string; //  name   string } //        props const App = (props: IAppProps) => { return ( <div className="container"> <h1>TZ #1 with hooks & TypeScript</h1> <nav> <p></p> </nav> <p> </p> <p>, {props.name}</p> </div> ) } 

name рдкреНрд░рдХрд╛рд░ рдХреЛ number рдмрджрд▓рдиреЗ рдХрд╛ рдкреНрд░рдпрд╛рд╕ рдХрд░реЗрдВ рдФрд░ рдПрдХ рддреНрд░реБрдЯрд┐ рддреБрд░рдВрдд рд╣реЛ рдЬрд╛рдПрдЧреАред



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


рд╣рдо props рдФрд░ рдПрдХ рдФрд░ props - рд╕рд╛рдЗрдЯ рдХреЛ <App /> рдЬреЛрдбрд╝ props


src / App.tsx


 interface IAppProps { name: string; } const App = (props: IAppProps) => { return ( <div className="container"> <h1>TZ #1 with hooks & TypeScript</h1> <nav> <p></p> </nav> <p> </p> <p>, {props.name}</p> {/*  site */} <p>: {props.site}</p> </div> ) } //  site const RoutedApp = () => { return <App name="Max Frontend" site="maxpfrontend.ru" /> } 

рдПрдХ рддреНрд░реБрдЯрд┐ рдорд┐рд▓реА:


 Type error: Property 'site' does not exist on type 'IAppProps'. TS2339 

site рд╕рдВрдкрддреНрддрд┐ IAppProps рдкреНрд░рдХрд╛рд░ рдореЗрдВ рдореМрдЬреВрдж рдирд╣реАрдВ рд╣реИред рдпрд╣рд╛рдВ, рдореИрдВ рддреБрд░рдВрдд рдХрд╣рдирд╛ рдЪрд╛рд╣рддрд╛ рд╣реВрдВ рдХрд┐ рдЯрд╛рдЗрдк рдирд╛рдо рд╕реЗ рд╣рдо рддреБрд░рдВрдд рд╕рдордЭ рдЬрд╛рддреЗ рд╣реИрдВ рдХрд┐ рдХрд╣рд╛рдВ рджреЗрдЦрдирд╛ рд╣реИред рдЗрд╕рд▓рд┐рдП, рдкреНрд░рдХрд╛рд░реЛрдВ рдХреЛ рд╕рд╣реА рдврдВрдЧ рд╕реЗ рдирд╛рдо рджреЗрдВред


рдЗрд╕рд╕реЗ рдкрд╣рд▓реЗ рдХрд┐ рд╣рдо рдЗрд╕реЗ рдареАрдХ рдХрд░ рджреЗрдВ, рдРрд╕рд╛ рдХрд░рддреЗ рд╣реИрдВ: рдЙрд╕ рдЕрдиреБрдЪреНрдЫреЗрдж рдХреЛ рд╣рдЯрд╛ рджреЗрдВ рдЬреЛ props.site ред


рд╣рдореЗрдВ рдПрдХ рдФрд░ рддреНрд░реБрдЯрд┐ рдкрд╛рда рдорд┐рд▓рддрд╛ рд╣реИ:



рдпрд╣рд╛рдВ рдореИрдВ рдХреЗрд╡рд▓ рд╡рд╣реА рдиреЛрдЯ рдХрд░рдирд╛ рдЪрд╛рд╣рддрд╛ рд╣реВрдВ рдЬреЛ рдЯреАрдПрд╕ рдиреЗ рдХрдЯреМрддреА рдХреА рдереА: site рдПрдХ рдкреНрд░рдХрд╛рд░ рдХрд╛ string (рдпрд╣ рд╕реНрдХреНрд░реАрдирд╢реЙрдЯ рдореЗрдВ рд░реЗрдЦрд╛рдВрдХрд┐рдд рд╣реИ)ред


рдареАрдХ:


 interface IAppProps { name: string; site: string; //    } const App = (props: IAppProps) => { return ( <div className="container"> <h1>TZ #1 with hooks & TypeScript</h1> <nav> <p></p> </nav> <p> </p> <p>, {props.name}</p> <p>: {props.site}</p> </div> ) } const RoutedApp = () => { return <App name="Max Frontend" site="maxpfrontend.ru" /> } 

рдХреЛрдИ рдЧрд▓рддреА рдирд╣реАрдВ, рдХреЛрдИ рд╕рдорд╕реНрдпрд╛ рдирд╣реАрдВред


рд░реВрдЯрд┐рдВрдЧ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдореЗрдВ рдмрдЪреНрдЪреЛрдВ рдХреЗ рдкреНрд░рддрд┐рдкрд╛рджрди рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рдЪрд▓реЛ рдЦреБрдж рд╕реЗ рдЖрдЧреЗ рдирд┐рдХрд▓рддреЗ рд╣реИрдВ рдФрд░ рдПрдХ "рдмрд╛рд▓ рдШрдЯрдХ" рдЦреАрдВрдЪрдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХрд░рддреЗ рд╣реИрдВред


 const App = (props: IAppProps) => { return ( <div className="container"> <h1>TZ #1 with hooks & TypeScript</h1> ... //  <p>: {props.site}</p> {props.children} </div> ) } const Baby = () => { return <p> </p> } const RoutedApp = () => { return ( <App name="Max Frontend" site="maxpfrontend.ru"> <Baby /> </App> ) } 

рдЯреАрдПрд╕ рд╢рдкрде рд▓реЗрддреЗ рд╣реИрдВ, рд╡реЗ рдРрд╕рд╛ рдХрд╣рддреЗ children - children IAppProps рдореЗрдВ рд╡рд░реНрдгрд┐рдд рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИред



рдмреЗрд╢рдХ, рд╣рдо рдХреБрдЫ рдорд╛рдирдХ рдЪреАрдЬреЛрдВ рдХреЛ "рдЯрд╛рдЗрдк" рдирд╣реАрдВ рдХрд░рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ, рдФрд░ рдпрд╣рд╛рдВ рд╕рдореБрджрд╛рдп рдмрдЪрд╛рд╡ рдХреЗ рд▓рд┐рдП рдЖрддрд╛ рд╣реИ, рдЬреЛ рд╣рдорд╛рд░реЗ рд╕рд╛рдордиреЗ рдмрд╣реБрдд рдкрд╣рд▓реЗ рд╣реА рдЯрд╛рдЗрдк рдХрд░ рдЪреБрдХрд╛ рд╣реИред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, @ рдкреНрд░рдХрд╛рд░ / рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдкреИрдХреЗрдЬ рдореЗрдВ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдХреЗ рд▓рд┐рдП рд╕рднреА рдкреНрд░рдХрд╛рд░ рд╣реИрдВред


рдЗрд╕ рдкреИрдХреЗрдЬ рдХреЛ рд╕реНрдерд╛рдкрд┐рдд рдХрд░рдХреЗ (рдореЗрд░реЗ рдЙрджрд╛рд╣рд░рдг рдореЗрдВ, рдпрд╣ рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рд╕реНрдерд╛рдкрд┐рдд рд╣реИ), рд╣рдо рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдкреНрд░рд╡рд┐рд╖реНрдЯрд┐ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ:


 React.FunctionComponent<P>    React.FC<P> 

рдЬрд╣рд╛рдВ <P> рд╣рдорд╛рд░реЗ props рд▓рд┐рдП рдкреНрд░рдХрд╛рд░ рд╣реИрдВ, рдЕрд░реНрдерд╛рдд, рд░рд┐рдХреЙрд░реНрдб рдлреЙрд░реНрдо рд▓реЗрдЧрд╛ред


 React.FC<IAppProps> 

рдЙрди рд▓реЛрдЧреЛрдВ рдХреЗ рд▓рд┐рдП рдЬреЛ рдЕрднреНрдпрд╛рд╕ рдХреЗ рдмрдбрд╝реЗ рд╕рдВрд╕реНрдХрд░рдгреЛрдВ рдХреЛ рдкрдврд╝рдиреЗ рдХреЗ рд╢реМрдХреАрди рд╣реИрдВ, рдЕрднреНрдпрд╛рд╕ рдХрд░рдиреЗ рд╕реЗ рдкрд╣рд▓реЗ, рдореИрдВ " рдЬреЗрдирд░рд┐рдХ " (рдЙрди <рдФрд░>) рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдПрдХ рд▓реЗрдЦ рдкреНрд░рд╕реНрддреБрдд рдХрд░ рд╕рдХрддрд╛ рд╣реВрдВред рдмрд╛рдХреА рдХреЗ рд▓рд┐рдП, рдЕрднреА рдХреЗ рд▓рд┐рдП, рдпрд╣ рдкрд░реНрдпрд╛рдкреНрдд рд╣реИ рдХрд┐ рд╣рдо рдЗрд╕ рд╡рд╛рдХреНрдпрд╛рдВрд╢ рдХреЛ рдЗрд╕ рддрд░рд╣ рдЕрдиреБрд╡рд╛рдж рдХрд░рддреЗ рд╣реИрдВ: рдПрдХ рдХрд╛рд░реНрдпрд╛рддреНрдордХ рдШрдЯрдХ рдЬреЛ рдЗрд╕ рддрд░рд╣ рдХреЗ <- рдФрд░ - рдРрд╕реЗ рдЧреБрдгреЛрдВ рдХреЛ рд╕реНрд╡реАрдХрд╛рд░ рдХрд░рддрд╛ рд╣реИ>ред


рдРрдк рдШрдЯрдХ рдХреЗ рд▓рд┐рдП рдкреНрд░рд╡рд┐рд╖реНрдЯрд┐ рдереЛрдбрд╝рд╛ рдмрджрд▓ рдЬрд╛рдПрдЧреАред рдкреВрд░реНрдг рд╕рдВрд╕реНрдХрд░рдгред


src / App.tsx


 //    ,     //      React     React.XXX, //  XXX -    import * as React from 'react' //  ,    ,     //  @types/react //     interface IAppProps { name: string; site: string; } //   const App: React.FC<IAppProps> = props => { return ( <div className="container"> <h1>TZ #1 with hooks & TypeScript</h1> <nav> <p></p> </nav> <p> </p> <p>, {props.name}</p> <p>: {props.site}</p> {props.children} </div> ) } const Baby = () => { return <p> </p> } const RoutedApp = () => { return ( <App name="Max Frontend" site="maxpfrontend.ru"> <Baby /> </App> ) } 

рдЖрдЗрдП рдирд┐рдореНрди рд╡рд░реНрдгреЛрдВ рдХреЛ рдкрдВрдХреНрддрд┐рдмрджреНрдз рдХрд░реЗрдВ:


 const App: React.FC<IAppProps> = props => { 

- props рдмрд╛рдж рдЯрд╛рдЗрдк рдХреНрдпреЛрдВ рдЧрд╛рдпрдм рд╣реЛ рдЧрдпрд╛?


- рдХреНрдпреЛрдВрдХрд┐, App рдмрд╛рдж - рдЬреЛрдбрд╝рд╛ рдЧрдпрд╛ред


рд╣рдордиреЗ рджрд░реНрдЬ рдХрд┐рдпрд╛ рдХрд┐ рдРрдк рд╡реИрд░рд┐рдПрдмрд▓ рдкреНрд░рдХрд╛рд░ рдХрд╛ рд╣реЛрдЧрд╛: React.FC<IAppProps> ред


React.FC "рдлрд╝рдВрдХреНрд╢рди" рдХрд╛ рдПрдХ рдкреНрд░рдХрд╛рд░ рд╣реИ, рдФрд░ рдЕрдВрджрд░ <> рд╣рдордиреЗ рд╕рдВрдХреЗрдд рджрд┐рдпрд╛ рдХрд┐ рдпрд╣ рдХрд┐рд╕ рдкреНрд░рдХрд╛рд░ рдХрд╛ рддрд░реНрдХ рд▓реЗрддрд╛ рд╣реИ, рдЕрд░реНрдерд╛рдд, рд╣рдордиреЗ рд╕рдВрдХреЗрдд рджрд┐рдпрд╛ рдХрд┐ рд╣рдорд╛рд░рд╛ props IAppProps рдкреНрд░рдХрд╛рд░ рдХрд╛ IAppProps ред


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


рдХреБрд▓: рд╣рдордиреЗ рд╕рдВрдЪрд░рд┐рдд props рд▓рд┐рдП рдЧреБрдгреЛрдВ рдХреЗ рдкреНрд░рдХрд╛рд░ рдХреЛ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд░рдирд╛ рд╕реАрдЦрд╛, рдЬрдмрдХрд┐ рд░рд┐рдПрдХреНрдЯ-рдШрдЯрдХреЛрдВ рдХреЗ "рдЙрдирдХреЗ" рдЧреБрдгреЛрдВ рдХреЛ рдирд╣реАрдВ рдЦреЛрдирд╛ред


рдлрд┐рд▓рд╣рд╛рд▓ рд╕реЛрд░реНрд╕ рдХреЛрдб ред


рд░реВрдЯрд┐рдВрдЧ рдЬреЛрдбрд╝реЗрдВ


рд╣рдо рдЕрдкрдиреЗ рдХреНрд╖рд┐рддрд┐рдЬ рдХреЛ рд╡реНрдпрд╛рдкрдХ рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдкрд╣реБрдВрдЪ-рд░рд╛рдЙрдЯрд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВрдЧреЗред рдпрд╣ рдкреИрдХреЗрдЬ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛-рд░рд╛рдЙрдЯрд░ рдХреЗ рд╕рдорд╛рди рд╣реИред


рдкреГрд╖реНрда рдЬреЛрдбрд╝реЗрдВ - рд╕рдорд╛рдЪрд╛рд░ (рд╕рдорд╛рдЪрд╛рд░), <App /> рдХреЛ рд╕рд╛рдлрд╝ рдХрд░реЗрдВред


src / Pages / News.tsx


 import * as React from 'react' const News = () => { return ( <div className="news"> <p></p> </div> ) } export { News } 

src / App.tsx


 import * as React from 'react' //    reach-router import { Link, Router } from '@reach/router' import { News } from './pages/News' import './App.css' interface IAppProps { name: string; site: string; } const App: React.FC<IAppProps> = props => { return ( <div className="container"> <h1>TZ #1 with hooks & TypeScript</h1> <nav> <Link to="/">Home</Link> <Link to="news">News</Link>{' '} </nav> <hr /> <p> {' '} : {props.name} | : {props.site} </p> <hr /> {props.children} </div> ) } //  Baby,  News.  app -  path const RoutedApp = () => { return ( <Router> <App path="/" name="Max Frontend" site="maxpfrontend.ru"> <News path="/news" /> </App> </Router> ) } export { RoutedApp } 

рдЕрдиреБрдкреНрд░рдпреЛрдЧ рдЯреВрдЯ рдЧрдпрд╛ рд╣реИ, рдПрдХ рддреНрд░реБрдЯрд┐ (рддреНрд░реБрдЯрд┐рдпреЛрдВ рдореЗрдВ рд╕реЗ рдПрдХ рд╣реИ, рдХреНрдпреЛрдВрдХрд┐ рдЯрд░реНрдорд┐рдирд▓ рдкрд╣рд▓реЗ рдПрдХ рдХреЛ рджрд┐рдЦрд╛рддрд╛ рд╣реИ):



рд╣рдо рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдЗрд╕ рд░рд┐рдХреЙрд░реНрдб рдХреЗ рд▓рд┐рдП рдЙрдкрдпреЛрдЧ рдХрд┐рдП рдЬрд╛рддреЗ рд╣реИрдВ, рдФрд░ рд╣рдо рдЗрд╕реЗ рд╕рдордЭрддреЗ рд╣реИрдВ рдХрд┐ path <App /> рд▓рд┐рдП рд╡рд┐рд╡рд░рдг рдореЗрдВ рдореМрдЬреВрдж рдирд╣реАрдВ рд╣реИред


рдлрд┐рд░, рд╣рдорд╛рд░реЗ рд╕рд╛рдордиреЗ рд╕рдм рдХреБрдЫ рд╡рд░реНрдгрд┐рдд рд╣реИред рд╣рдо @ рдЯрд╛рдЗрдк / рддрдХ рдкрд╣реБрдВрдЪ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВрдЧреЗ рдкреИрдХреЗрдЬ рдФрд░ RouteComponentProps рдкреНрд░рдХрд╛рд░ред рдЕрдкрдиреЗ рдЧреБрдгреЛрдВ рдХреЛ рди рдЦреЛрдиреЗ рджреЗрдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдо extends рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВрдЧреЗред


 import * as React from 'react' //   RouteComponentProps  - // ts  ,     import { Link, RouteComponentProps, Router } from '@reach/router' import { News } from './pages/News' import './App.css' // extends       RouteComponentProps //     interface IAppProps extends RouteComponentProps { name: string; site: string; } // ...    

рдЬрд┐рдЬреНрдЮрд╛рд╕реБ рдХреЗ рд▓рд┐рдП, RouteComponentProps рдореЗрдВ рдХрд┐рд╕ рдкреНрд░рдХрд╛рд░ рдХрд╛ рд╡рд░реНрдгрди рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ ред


<App /> рдореЗрдВ рддреНрд░реБрдЯрд┐ рдЧрд╛рдпрдм рд╣реЛ рдЧрдИ, рд▓реЗрдХрд┐рди <News /> рдореЗрдВ рдмрдиреА рд░рд╣реА, рдХреНрдпреЛрдВрдХрд┐ рд╣рдордиреЗ рдЗрд╕ рдШрдЯрдХ рдХреЗ рд▓рд┐рдП рдЯрд╛рдЗрдкрд┐рдВрдЧ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдирд╣реАрдВ рдХреА рдереАред


рдорд┐рдиреА рдкрд╣реЗрд▓реА: <News /> рд▓рд┐рдП рдЯрд╛рдЗрдкрд┐рдВрдЧ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд░реЗрдВред рдлрд┐рд▓рд╣рд╛рд▓, рд░рд╛рдЙрдЯрд░ рд╕реЗ рдХреЗрд╡рд▓ рдЧреБрдгреЛрдВ рдХреЛ рд╡рд╣рд╛рдВ рд╕реНрдерд╛рдирд╛рдВрддрд░рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред


рдЙрддреНрддрд░ рд╣реИ:


src / Pages / News.tsx


 import * as React from 'react' import { RouteComponentProps } from '@reach/router' //      RouteComponentProps //       P ( React.FC<P> ) const News: React.FC<RouteComponentProps> = () => { return ( <div className="news"> <p></p> </div> ) } export { News } 


рд╣рдо рдЖрдЧреЗ рдмрдврд╝рддреЗ рд╣реИрдВ рдФрд░ рдПрдХ рдкреИрд░рд╛рдореАрдЯрд░ рдХреЗ рд╕рд╛рде рдПрдХ рдорд╛рд░реНрдЧ рдЬреЛрдбрд╝рддреЗ рд╣реИрдВред рдкрд╣реБрдВрдЪ-рд░рд╛рдЙрдЯрд░ рдореЗрдВ рдкреИрд░рд╛рдореАрдЯрд░ рд╕реАрдзреЗ рдкреНрд░реЙрдкреНрд╕ рдореЗрдВ рд░рд╣рддреЗ рд╣реИрдВред рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛-рд░рд╛рдЙрдЯрд░ рдореЗрдВ, рдЬреИрд╕рд╛ рдХрд┐ рдЖрдкрдХреЛ рдпрд╛рдж рд╣реИ, рд╡реЗ props.match рдореЗрдВ рд░рд╣рддреЗ рд╣реИрдВред


src / App.tsx


 import * as React from 'react' import { Link, RouteComponentProps, Router } from '@reach/router' import { About } from './pages/About' import { News } from './pages/News' // ... () const RoutedApp = () => { return ( <Router> <App path="/" name="Max Frontend" site="maxpfrontend.ru"> <News path="/news" /> {/*     source */} <About path="/about/:source" /> </App> </Router> ) } export { RoutedApp } 

src / Pages / About.tsx


 import * as React from 'react' import { RouteComponentProps } from '@reach/router' const About: React.FC<RouteComponentProps> = props => { return ( <div className="about"> <p> about</p> {/*   source  */} <p>{props.source}</p> </div> ) } export { About } 

рдПрдХ рддреНрд░реБрдЯрд┐ рдЬрд┐рд╕рдХреА рд╣рдореЗрдВ рдЙрдореНрдореАрдж рдирд╣реАрдВ рдереА:



рд╕реНрд░реЛрдд рд╕рдВрдкрддреНрддрд┐ рдореМрдЬреВрдж рдирд╣реАрдВ рд╣реИ ... рдПрдХ рддрд░рдл, рдШрдмрд░рд╛рд╣рдЯ: рд╣рдо рдЗрд╕реЗ рдкрде рдкрд░ рднреЗрдЬрддреЗ рд╣реИрдВ, рдЬреЛ рд╕реНрдЯреНрд░рд┐рдВрдЧ рд╣реИ, рджреВрд╕рд░реА рдУрд░, рдЦреБрд╢реА: рдЖрд╣, рдареАрдХ рд╣реИ, рдХреИрд╕реЗ рдкреБрд╕реНрддрдХрд╛рд▓рдп рдХреЗ рд▓реЗрдЦрдХ рдФрд░ рдЯрд╛рдЗрдкрд┐рдВрдЧ рдиреЗ рдЗрд╕ рдЪреЗрддрд╛рд╡рдиреА рдХреЛ рд╣рдореЗрдВ рдЬреЛрдбрд╝рдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХреАред


рдЗрд╕реЗ рдареАрдХ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдо рд╡рд┐рдХрд▓реНрдкреЛрдВ рдореЗрдВ рд╕реЗ рдПрдХ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВрдЧреЗ: RouteComponentProps рд╕реЗ рд╡рд┐рд╕реНрддрд╛рд░ рдХрд░реЗрдВ рдФрд░ рд╡реИрдХрд▓реНрдкрд┐рдХ source рдЧреБрдг рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд░реЗрдВред рд╡реИрдХрд▓реНрдкрд┐рдХ, рдХреНрдпреЛрдВрдХрд┐ рдпрд╣ рд╣рдорд╛рд░реЗ URL рдореЗрдВ рдирд╣реАрдВ рд╣реЛ рд╕рдХрддрд╛ рд╣реИред


рдЯрд╛рдЗрдкрд╕реНрдХреНрд░рд┐рдкреНрдЯ рд╡реИрдХрд▓реНрдкрд┐рдХ рд╕рдВрдкрддреНрддрд┐ рдХреЛ рдЗрдВрдЧрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдкреНрд░рд╢реНрди рдЪрд┐рд╣реНрди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реИред


src / Pages / About.tsx


 import * as React from 'react' import { RouteComponentProps } from '@reach/router' interface IAboutProps extends RouteComponentProps { source?: string; //  source - ,      (    props.source  undefined) } const About: React.FC<IAboutProps> = props => { return ( <div className="about"> <p> about</p> <p>{props.source}</p> </div> ) } export { About } 

src / App.tsx (рдПрдХ рд╣реА рд╕рдордп рдореЗрдВ рд╣рдо рдиреЗрд╡рд┐рдЧреЗрд╢рди рдХреЛ рд╕рдВрддреБрд▓рд┐рдд рдХрд░реЗрдВрдЧреЗ)


 import * as React from 'react' import { Link, RouteComponentProps, Router } from '@reach/router' import { About } from './pages/About' import { News } from './pages/News' import './App.css' interface IAppProps extends RouteComponentProps { name: string; site: string; } const App: React.FC<IAppProps> = props => { return ( <div className="container"> <h1>TZ #1 with hooks & TypeScript</h1> <nav> <Link to="/"></Link> <Link to="news"></Link>{' '} <Link to="/about/habr"> habr</Link>{' '} </nav> <hr /> <p> {' '} : {props.name} | : {props.site} </p> <hr /> {props.children} </div> ) } const RoutedApp = () => { return ( <Router> <App path="/" name="Max Frontend" site="maxpfrontend.ru"> <News path="/news" /> <About path="/about/:source" /> </App> </Router> ) } export { RoutedApp } 


рдХреБрд▓ : рд╣рдордиреЗ рд░реЛрдЯреЗрд╢рди рдореЗрдВ рд╢рд╛рдорд┐рд▓ рдШрдЯрдХреЛрдВ рдХреЛ рдЯрд╛рдЗрдк рдХрд░рдирд╛ рд╕реАрдЦрд╛ред


рдлрд┐рд▓рд╣рд╛рд▓ рд╕реЛрд░реНрд╕ рдХреЛрдб ред




рдЪрд▓реЛ рд╣реБрдХ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рддреЗ рд╣реИрдВ рдФрд░ рдЯрд╛рдЗрдкрд┐рдВрдЧ рдЬрд╛рд░реА рд░рдЦрддреЗ рд╣реИрдВ


рдореИрдВ рдЖрдкрдХреЛ рдпрд╛рдж рджрд┐рд▓рд╛рддрд╛ рд╣реВрдВ рдХрд┐ рд╣рдорд╛рд░рд╛ рдХрд╛рдо рдПрдХ рдкрд░реАрдХреНрд╖рдг рдХрд╛рд░реНрдп рдХреЛ рд▓рд╛рдЧреВ рдХрд░рдирд╛ рд╣реИ , рд▓реЗрдХрд┐рди Redux рдХреЗ рдмрд┐рдирд╛ред


рдореИрдВрдиреЗ рдЗрд╕ рдЪрд░рдг рдХреЛ рд░реВрдЯрд┐рдВрдЧ, рдПрдХ рдЧреИрд░-рдХрд╛рд░реНрдпрд╢реАрд▓ рд▓реЙрдЧрд┐рди рдлрд╝реЙрд░реНрдо рдФрд░ рдЖрд╡рд╢реНрдпрдХ рдкреГрд╖реНрдареЛрдВ рдХреЗ рд╕рд╛рде рд╢реБрд░реВ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рд╢рд╛рдЦрд╛ рддреИрдпрд╛рд░ рдХреАред



рд╕рдорд╛рдЪрд╛рд░ рдбрд╛рдЙрдирд▓реЛрдб рдХрд░реЗрдВ


рд╕рдорд╛рдЪрд╛рд░ рд╡рд╕реНрддреБрдУрдВ рдХреА рдПрдХ рд╕рд░рдгреА рд╣реИред


рдкреНрд░рд╕реНрддреБрдд рд╣реИ рд╣рдорд╛рд░реА рдЦрдмрд░:


 { id: 1, title: ' CRUD    React-hooks', text: '     CRUD-  ', link: 'https://maxpfrontend.ru/perevody/delaem-crud-prilozhenie-s-pomoschyu-react-hooks/', timestamp: new Date('01-15-2019'), }, 

рдЖрдЗрдП рдПрдХ рдореЙрдбрд▓ рддреБрд░рдВрдд рд▓рд┐рдЦреЗрдВ (рд╕рдорд╛рдЪрд╛рд░ рдХреЗ рд▓рд┐рдП рдкреНрд░рдХрд╛рд░):


src / рдореЙрдбрд▓ / news.ts ( .ts рдПрдХреНрд╕рдЯреЗрдВрд╢рди)


 export interface INewsItem { id: number; title: string; text: string; link: string; timestamp: Date; } 

рдирдП рд╕реЗ - рдЯрд╛рдЗрдорд╕реНрдЯреИрдореНрдк рдиреЗ Date рд╕рдВрдХреЗрдд рджрд┐рдпрд╛ред


рд╣рдорд╛рд░реЗ рдбреЗрдЯрд╛ рдХреЙрд▓ рдХреА рдХрд▓реНрдкрдирд╛ рдХрд░реЗрдВ:


 const fakeData = [ { id: 1, title: ' CRUD    React-hooks', text: '     CRUD-  ', link: 'https://maxpfrontend.ru/perevody/delaem-crud-prilozhenie-s-pomoschyu-react-hooks/', timestamp: new Date('01-15-2019'), }, { id: 2, title: '  React hooks', text: '      useState  useEffect ', link: 'https://maxpfrontend.ru/perevody/znakomstvo-s-react-hooks/', timestamp: new Date('01-06-2019'), }, { id: 3, title: '   Google Sign In', text: '   Google Sign In  ', link: 'https://maxpfrontend.ru/vebinary/avtorizatsiya-s-pomoschyu-google-sign-in/', timestamp: new Date('11-02-2018'), }, ] export const getNews = () => { const promise = new Promise(resolve => { resolve({ status: 200, data: fakeData, //    }) }) return promise //  promise } 

рдПрдкреАрдЖрдИ рд╕реЗ рд╣рдорд╛рд░рд╛ рдХреЙрд▓ getNews рд░рд┐рдЯрд░реНрди рдкреНрд░реЛрдорд┐рд╕ рд╣реИ , рдФрд░ рдЗрд╕ "рдкреНрд░реЙрдорд┐рд╕" рдореЗрдВ рдПрдХ рдирд┐рд╢реНрдЪрд┐рдд рдкреНрд░рдХрд╛рд░ рд╣реИ, рдЬрд┐рд╕рдХрд╛ рд╣рдо рд╡рд░реНрдгрди рднреА рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ:


 interface INewsResponse { status: number; //  -  data: INewsItem[]; // data -  ,    INewsItem [1] errorText?: string; // ,   errorText  ,     } // [1] ,   models      export interface INewsItem { id: number; title: string; text: string; link: string; timestamp: Date; } //   __[] -      __ // [{__}, {__}, {__}] 

рдХреНрдпрд╛ рдпрд╣ рдЧрд░реНрдо рд╣реИ? рдЕрдм рдпрд╣ рдФрд░ рднреА рдЧрд░реНрдо рд╣реЛрдЧрд╛, рдХреНрдпреЛрдВрдХрд┐ рд╡рд╛рджрд╛ рдкреНрд░рдХрд╛рд░ рдПрдХ рд╕рд╛рдорд╛рдиреНрдп рд╣реИ, рд╣рдореЗрдВ рдлрд┐рд░ рд╕реЗ < рдФрд░ > рд╕реЗ рдирд┐рдкрдЯрдирд╛ рд╣реЛрдЧрд╛ред рдпрд╣ рдЯреНрдпреВрдЯреЛрд░рд┐рдпрд▓ рдХрд╛ рд╕рдмрд╕реЗ рдХрдард┐рди рд╣рд┐рд╕реНрд╕рд╛ рд╣реИ, рдЗрд╕рд▓рд┐рдП рд╣рдордиреЗ рдЕрдВрддрд┐рдо рдХреЛрдб рдкрдврд╝рд╛:


src / api / News.ts


 import { INewsItem } from '../models/news' //    interface INewsResponse { //    __ status: number; data: INewsItem[]; errorText?: string; } const fakeData = [ //...  ] //    //    : // const myFunc = ():__ { return _ } // getNews -  ,    () ( ) //    Promise //   Promise -  generic,   : //  Promise<T>,  T -  ,     [1] //   ,  T ,   - INewsResponse export const getNews = (): Promise<INewsResponse> => { //  ,  [1] const promise = new Promise<INewsResponse>(resolve => { // [2] resolve({ status: 200, data: fakeData, }) }) return promise //    promise [2]  Promise<INewsResponse> } 

рдзреБрдЖрдВ рдЯреВрдЯрдирд╛ред


рдЦрдмрд░ рджрд┐рдЦрд╛рдУ


src / Pages / News.tsx


 import * as React from 'react' import { RouteComponentProps } from '@reach/router' import { getNews } from '../api/news' import { NewsItem } from '../components/NewsItem' //    import { INewsItem } from '../models/news' const News: React.FC<RouteComponentProps> = () => { // useState -   ,     T //   ,  T -    INewsItem //  ,    ,     [] const [news, setNews] = React.useState<INewsItem[]>([]) // <-       React.useEffect(() => { getNews() .then(res => { setNews(res.data) }) .catch(err => { //   TSLint     console.log // , ""     // tslint:disable-next-line: no-console console.warn('Getting news problem', err) }) }, []) return ( <div className="news"> {news.map(item => ( <NewsItem data={item} key={item.id} /> ))} </div> ) } export { News } 

рдХреЛрдб рдЯрд┐рдкреНрдкрдгреА рджреЗрддрд╛ рд╣реИ рдЬреЛ рдЯрд╛рдЗрдкрд╕реНрдХреНрд░рд┐рдкреНрдЯ рд╕реЗ рд╕рдВрдмрдВрдзрд┐рдд рд╣реИред рдпрджрд┐ рдЖрдкрдХреЛ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛-рд╣реБрдХ рдХреЗ рд╕рд╛рде рдорджрдж рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ, рддреЛ рдЖрдк рдпрд╣рд╛рдВ рдкрдврд╝ рд╕рдХрддреЗ рд╣реИрдВ: рдкреНрд░рд▓реЗрдЦрди (рдИрдПрди), рдЯреНрдпреВрдЯреЛрд░рд┐рдпрд▓ (рдЖрд░рдпреВ)ред


рдХрд╛рд░реНрдп: рдПрдХ <NewsItem /> рдШрдЯрдХ рд▓рд┐рдЦреЗрдВ рдЬреЛ рд╕рдорд╛рдЪрд╛рд░ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░реЗрдЧрд╛ред рд╕рд╣реА рдкреНрд░рдХрд╛рд░ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд░рдирд╛ рдпрд╛рдж рд░рдЦреЗрдВред INewsItem рдореЙрдбрд▓ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВред


рдкрд░рд┐рдгрд╛рдо рдЗрд╕ рддрд░рд╣ рджрд┐рдЦ рд╕рдХрддрд╛ рд╣реИ:



рд╕рдорд╛рдзрд╛рди рдиреАрдЪреЗ рд╣реИред


src / Components / NewsItem.tsx


 import * as React from 'react' import { INewsItem } from '../models/news' interface INewsItemProps { data: INewsItem; // [1] } // [2] const NewsItem: React.FC<INewsItemProps> = ({ data: { title, text, timestamp, link }, }) => { return ( <article> <br /> <div> { <a href={link} target="_blank"> {title} </a> }{' '} | {timestamp.toLocaleDateString()} </div> <div>{text}</div> </article> ) } export { NewsItem } 

рд╕рд╡рд╛рд▓ рдпрд╣ рд╣реИ рдХрд┐ рд╣рдордиреЗ рдЗрд╕ рддрд░рд╣ рд╕реЗ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдХрд╛ рд╡рд░реНрдгрди рдХрд┐рдпрд╛ (рдХреЛрдб [1] рдФрд░ [2] рдореЗрдВ рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдВ)ред рдХреНрдпрд╛ рд╣рдо рд╕рд┐рд░реНрдл рд▓рд┐рдЦ рд╕рдХрддреЗ рд╣реИрдВ:


 React.FC<INewsItem> 

рдЬрд╡рд╛рдм рдиреАрдЪреЗ рд╣реИред


ред


ред


ред


рдЪреВрдВрдХрд┐, рд╣рдо data рдкреНрд░реЙрдкрд░реНрдЯреА рдореЗрдВ рд╕рдорд╛рдЪрд╛рд░ рдкрд╛рд░рд┐рдд рдХрд░ рд░рд╣реЗ рд╣реИрдВ, рдЕрд░реНрдерд╛рдд рд╣рдореЗрдВ рд▓рд┐рдЦрдирд╛ рд╣реЛрдЧрд╛:


 React.FC<{ data: INewsItem }> 

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


рдХреБрд▓: рд╣рдордиреЗ рд╡рд╛рджрд╛ рдФрд░ рдЙрдкрдпреЛрдЧ рдХреЗ рд▓рд┐рдП рдЯрд╛рдЗрдкрд┐рдВрдЧ рдХрд╛ рдЕрднреНрдпрд╛рд╕ рдХрд┐рдпрд╛ред рдЕрдиреНрдп рдШрдЯрдХ рдХреЗ рд▓рд┐рдП рдкреНрд░рдХрд╛рд░ рдХрд╛ рд╡рд░реНрдгрди рдХрд┐рдпрд╛ред


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


рдлрд┐рд▓рд╣рд╛рд▓ рд╕реЛрд░реНрд╕ рдХреЛрдб ред




рдЕрдерд┐ рдЖрдкрд┐


рд▓реЙрдЧрд┐рди рдХреЗ рд▓рд┐рдП api рд▓рд┐рдЦреЗрдВред рд╕рд┐рджреНрдзрд╛рдВрдд рд╕рдорд╛рди рд╣реИ - рд╣рдо рдЙрддреНрддрд░ рдЕрдзрд┐рдХреГрдд / рддреНрд░реБрдЯрд┐ рдХреЗ рд╕рд╛рде рдПрдХ promise рд╡рд╛рдкрд╕ рдХрд░рддреЗ рд╣реИрдВред рд╣рдо localStorage рдореЗрдВ рдкреНрд░рд╛рдзрд┐рдХрд░рдг рд╕реНрдерд┐рддрд┐ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЬрд╛рдирдХрд╛рд░реА рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд░реЗрдВрдЧреЗ ( рдХрдИ рдЗрд╕реЗ рд╕реБрд░рдХреНрд╖рд╛ рдХрд╛ рдПрдХ рдкреНрд░рдореБрдЦ рдЙрд▓реНрд▓рдВрдШрди рдорд╛рдирддреЗ рд╣реИрдВ, рдореИрдВ рд╡рд┐рд╡рд╛рджреЛрдВ рд╕реЗ рдереЛрдбрд╝рд╛ рдкреАрдЫреЗ рд╣реВрдВ рдФрд░ рдпрд╣ рдирд╣реАрдВ рдЬрд╛рдирддрд╛ рдХрд┐ рдпрд╣ рдХреИрд╕реЗ рд╕рдорд╛рдкреНрдд рд╣реБрдЖ )ред


рд╣рдорд╛рд░реЗ рдЖрд╡реЗрджрди рдореЗрдВ, рд▓реЙрдЧрд┐рди рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдирд╛рдо рдФрд░ рдкрд╛рд╕рд╡рд░реНрдб рдХрд╛ рдПрдХ рдЧреБрдЪреНрдЫрд╛ рд╣реИ (рджреЛрдиреЛрдВ рд╕реНрдЯреНрд░рд┐рдВрдЧ рд╣реИрдВ), рд╣рдо рдореЙрдбрд▓ рдХрд╛ рд╡рд░реНрдгрди рдХрд░реЗрдВрдЧреЗ:


src / рдореЙрдбрд▓ / user.ts


 export interface IUserIdentity { username: string; password: string; } 

src / api / schem.ts


 import { navigate } from '@reach/router' import { IUserIdentity } from '../models/user' //        //    data -  any ( ,  ) // ,    ,      , //    ,      ( ) interface IAuthResponse { status: number; data?: any; [1] errorText?: string; } // -,  -      //      IUserIdentity //    -  boolean  (true  false) const checkCredentials = (data: IUserIdentity): boolean => { if (data.username === 'Admin' && data.password === '12345') { return true } else { return false } } //   "-",    ,       //    ,      1  - data //    Promise<T>,  T -  IAuthResponse export const authenticate = (data: IUserIdentity): Promise<IAuthResponse> => { const promise = new Promise<IAuthResponse>((resolve, reject) => { if (!checkCredentials(data)) { reject({ status: 500, errorText: 'incorrect_login_or_password', }) } window.localStorage.setItem('tstz.authenticated', 'true') resolve({ status: 200, data: 'ok', //    -  string,     IAuthResponse [1] any  string }) }) return promise } //   ,    //  0  () //  true  false ( boolean) export const checkAuthStatus = (): boolean => { if (localStorage.getItem('tstz.authenticated')) { return true } else { return false } } //   ,  0  //    (    void) export const logout = (): void => { window.localStorage.removeItem('tstz.authenticated') navigate('/') //      url- (reach-router) } 

, .


:




: . useState . event onChange / onSubmit тАФ any . .


React.useState тАФ , ( React.useState<T> )


, , , . , /profile ( navigate )


.


ред


ред


ред


ред


src/pages/Login.tsx


 import * as React from 'react' import { navigate, RouteComponentProps } from '@reach/router' import { authenticate } from '../api/auth' import { IUserIdentity } from '../models/user' //    ,     //      < > const Login: React.FC<RouteComponentProps> = () => { // useStaet  ,   useEffect - , //    ,     state const [user, setField] = React.useState<IUserIdentity>({ username: '', password: '', }) // ,    ( )  "" const [notification, setNotification] = React.useState<string>('') //  e (event) ,   <input /> //   : React.SyntheticEvent<HTMLInputElement> const onInputChange = (fieldName: string) => ( e: React.SyntheticEvent<HTMLInputElement> ): void => { setField({ ...user, [fieldName]: e.currentTarget.value, }) setNotification('') } //  e (event) ,    form //   : React.SyntheticEvent<HTMLFormElement> const onSubmit = (e: React.SyntheticEvent<HTMLFormElement>): void => { e.preventDefault() authenticate(user) .then(() => { navigate(`/profile`) //   profile }) .catch(err => { if (err.errorText) { setNotification(err.errorText) } else { // tslint:disable-next-line: no-console console.warn('request problem', err) } }) } return ( <> <h2>Login</h2> <form onSubmit={onSubmit}> {notification ? <p>{notification}</p> : null} <input type="text" value={user.username} onChange={onInputChange('username')} /> <input type="text" value={user.password} onChange={onInputChange('password')} /> <button>Login</button> </form> </> ) } export { Login } 

, TS тАФ . , , JavaScript.


: useState event


тЖТ



TypeScript' , .


, reach-router , react-router. , , , .


src/components/common/Authenticated.tsx


 import * as React from 'react' import { Redirect, RouteComponentProps } from '@reach/router' import { checkAuthStatus } from '../../api/auth' //  noThrow    - https://reach.tech/router/api/Redirect const Authenticated: React.FC<RouteComponentProps> = ({ children }) => { return checkAuthStatus() ? ( <React.Fragment>{children}</React.Fragment> ) : ( <Redirect to="/login" noThrow={true} /> ) } export { Authenticated } 

src/App.tsx


 import * as React from 'react' import { Link, RouteComponentProps, Router } from '@reach/router' import { Authenticated } from './components/ommon/Authenticated' import { Home } from './pages/Home' import { Login } from './pages/Login' import { News } from './pages/News' import { Profile } from './pages/Profile' import { checkAuthStatus, logout } from './api/auth' import './App.css' const App: React.FC<RouteComponentProps> = props => { return ( <div className="container"> <h1>TZ #1 with hooks & TypeScript</h1> <nav> <Link to="/"></Link> <Link to="news"></Link>{' '} <Link to="profile"></Link>{' '} {checkAuthStatus() ? <button onClick={logout}></button> : null} </nav> {props.children} </div> ) } const RoutedApp = () => { return ( <Router> <App path="/"> <Home path="/" /> <Login path="/login" /> <News path="/news" /> <Authenticated path="/profile"> <Profile path="/" /> </Authenticated> </App> </Router> ) } export { RoutedApp } 

.


. type="password" .




, . "-", , , react-intl , react-i18next .


, . :


src/localization/formErrors.ts


 const formErrors = { ru: { incorrect_login_or_password: '      ', }, en: { incorrect_login_or_password: 'Incorrect login or password', }, } export { formErrors } 

<Login />


src/pages/Login.tsx


 import * as React from 'react' import { navigate, RouteComponentProps } from '@reach/router' import { authenticate } from '../api/auth' //   import { formErrors } from '../localization/formErrors' import { IUserIdentity } from '../models/user' //    const lang = 'ru' const Login: React.FC<RouteComponentProps> = () => { // ...  const onSubmit = (e: React.SyntheticEvent<HTMLFormElement>): void => { e.preventDefault() authenticate(user) .then(() => { navigate(`/profile`) }) .catch(err => { if (err.errorText) { //      (  ,  ru) setNotification(formErrors[lang][err.errorText]) } else { // tslint:disable-next-line: no-console console.warn('request problem', err) } }) } // ...  } export { Login } 

, .



TypeScript , , . , index signature ( , StackOverflow ).


 interface IFormErrors { [key: string]: { [key: string]: string, }; } const formErrors: IFormErrors = { ru: { incorrect_login_or_password: '      ', }, en: { incorrect_login_or_password: 'Incorrect login or password', }, } export { formErrors } 

, . , "".



тЖТ




рдирд┐рд╖реНрдХрд░реНрд╖


TypeScript. , TS . , , "one" "two" ( тАФ union).


, тАФ .


" " telegram youtube ( 11 2019).


рдЖрдкрдХрд╛ рдзреНрдпрд╛рди рдХреЗ рд▓рд┐рдП рдзрдиреНрдпрд╡рд╛рдж! , :




CRA + TypeScript


TypeScript Playground


тАФ Understanding TypeScript's type notation ( Dr.Axel Rauschmayer)


Microsoft,


TSLint


tslint


tslint


tsconfig.json tslint.json


d.ts .ts


, staging .



react-typescript-samples LemonCode


:


es5 (!)


React v16


typescript-.


Microsoft. UI- Fabric . , github .

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


All Articles