ããã«ã¡ã¯Habrã仿¥ã¯TypeScriptãšReact-hooksã䜿ã£ãŠè§£æ±ºããŸãã ãã®ãã¥ãŒããªã¢ã«ã¯ããã¹ã¯ãªãããã®åºæ¬ãçè§£ããã®ã«åœ¹ç«ã¡ãããã³ããšã³ãã®ãã¹ãã¿ã¹ã¯ã«åãçµãã®ã«åœ¹ç«ã¡ãŸãã
ãæ°Žãªãããããžã§ã¯ãã®ãã¹ãã¿ã¹ã¯ã¯ãã³ãŒãã¬ãã¥ãŒãååŸããæ©äŒã§ãã çŸåšã®å²ãåœãŠã®ç· ãåãã¯2019幎4æ11æ¥ã§ãã

ãããªç
èªãã®ãé¢åãªå Žåã¯ã3æ20æ¥ã®ã¢ã¹ã¯ã¯æé21:00ã«ãŠã§ãããŒã«ã¢ã¯ã»ã¹ããŠãã ããã ç»é² ïŒé»åã¡ãŒã«ããã³SMSãªãïŒã ãŠã§ãããŒéå¬ããŠã§ãããŒé²ç» ã
æºåãã
éå§ããã«ã¯ã Create-react-app TypeScriptããŒãžã§ã³ã䜿çšããããã¹ã¿ãŒã¿ãŒ ïŒæ¢ã«reach-routerãå«ãŸããŠããŸãïŒã䜿çšããŸã
ã¹ã¿ãŒã¿ãŒã䜿çšããŸãïŒããã«ã€ããŠã¯ããæŒç¿ãã»ã¯ã·ã§ã³ã§è©³ãã説æããŸãïŒã
TypeScriptçè«
TSã¯ã倿°ãç°ãªãå€ããšãããšãã§ããå Žåã®JavaScriptã®ãåçåä»ããã®åé¡ã解決ããŸãã æååãæ°å€ããŸãã¯ãªããžã§ã¯ãã§ãã ã19äžçŽãã§æžãã®ã¯éåžžã«äŸ¿å©ã§ããããå®çŸ©æžã¿ã®ã¿ã€ãïŒã«ãŒã«ãèæ
®ããïŒãããã°ãã³ãŒãããŒã¹ã®ä¿å®ã容æã«ãªãããšã«èª°ããåæããŸãã ãŸããéçºæ®µéã§ã®ãã°ãå°ãªããªããŸãã
ããšãã°ã1ã€ã®ãã¥ãŒã¹ã¢ã€ãã ã衚瀺ããã³ã³ããŒãã³ããããå Žåããã¥ãŒã¹ã¢ã€ãã ã«æ¬¡ã®ã¿ã€ããæå®ã§ããŸãã
ãããã£ãŠãããã¥ãŒã¹ããªããžã§ã¯ãã®ããããã£ã«å³å¯ãªãéçãã¿ã€ããæå®ããŸããã ååšããªãããããã£ãååŸããããšãããšãTypeScriptã¯ãšã©ãŒã衚瀺ããŸãã
import * as React from 'react' import { INewsItem } from '../models/news'

ãŸããVisual Studio Codeããã³ãã®ä»ã®é«åºŠãªãšãã£ã¿ãŒã§ãšã©ãŒã衚瀺ãããŸãã

èŠèŠçã«ã䟿å©ã ç§ã®å ŽåãVS Codeã¯2ã€ã®ãšã©ãŒãäžåºŠã«è¡šç€ºããŸãã倿°ã®ã¿ã€ããèšå®ãããŠããªãïŒã€ãŸãããã€ã³ã¿ãŒãã§ãŒã¹ããã¥ãŒã¹ã«ååšããªãïŒãšã倿°ã䜿çšãããŠããªãã ããã«ãTypeScriptã䜿çšãããšãã«äœ¿çšãããªã倿°ã¯ãããã©ã«ãã§VS Codeã§æ·¡è²ã§åŒ·èª¿è¡šç€ºãããŸãã
ããã§ãTypeScriptãšVS Codeã®ãã®ãããªå¯æ¥ãªçµ±åã®çç±ã1è¡ã§ç€ºãããšã¯äŸ¡å€ããããŸããäž¡æ¹ã®è£œåã¯Microsoftã®éçºã§ãã
TypeScriptã§ããã«ãããããšã¯äœã§ããïŒ å€æ°ã®ã³ã³ããã¹ãã§èšãã°ãããã ãã§ãã TSã¯éåžžã«åŒ·åã§ãäœãäœã§ããããçè§£ããŠããŸãã
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> ) }

ããã§ãTypeScriptã¯ãååšããªãããããã£toUpperCase
ãããã«èªããŸãã ãããŠãç§ãã¡ãç¥ã£ãŠããããã«ãå®éã toUpperCaseïŒïŒã¡ãœãããæã€ã®ã¯æåååã®ã¿ã§ãã
ããã§ããã颿°ã®ååãæžãå§ãããã©ã±ãããéããšãããã«ãããã¢ãããã«ããŠã£ã³ããŠã衚瀺ããã颿°ã«æž¡ãããšãã§ããåŒæ°ãšåã瀺ããŸãã
ãŸãã¯æ³åããŠã¿ãŠãã ãã-å³å¯ã«æšå¥šäºé
ã«åŸã£ãã®ã§ããããžã§ã¯ããžã®å
¥åã¯é²åŒŸã§ãã èªå眮æã«å ããŠããããžã§ã¯ãã®æé»çãªïŒ undefined
ïŒå€ã®åé¡ãåãé€ããŸãã
ç·Žç¿ãã
react-hooks + TypeScriptã§æåã®ãã¹ãã¿ã¹ã¯ãæžãçŽããŸãã ãšããããReduxãçç¥ããŸãããããã以å€ã®å Žåã¯ãã restarted TKïŒ1 ãã«åãçµã代ããã«ããããããã¹ãŠãã³ããŒããŸãã
ããŒã«ããã
ïŒ VS Codeã䜿çšãã人åãïŒ
䟿å®äžã TSLintæ¡åŒµæ©èœãã€ã³ã¹ããŒã«ããããšããå§ãããŸãã
ä¿åæã«TSLintãšã©ãŒã®èªåä¿®æ£ãæå¹ã«ããã«ã¯ããšãã£ã¿ãŒèšå®ã«è¿œå ããŸãã
ã¡ãã¥ãŒããèšå®ã«ã¢ã¯ã»ã¹ãããããªãã¬ãŒãã£ã³ã°ã·ã¹ãã ã®ç©ççãªå Žæã確èªãããã§ããŸãã
TSLintèšå®ã¯æšæºã§ãããããã«1ã€ã®ã«ãŒã«ãç¡å¹ã«ããŸããã
{ "extends": ["tslint:recommended", "tslint-react", "tslint-config-prettier"], "linterOptions": { "exclude": [ "node_modules/**/*.ts", "src/serviceWorker.js" ] }, "rules": { "object-literal-sort-keys": false
çµ±åã¯çµäºããŸããïŒ
ã¢ããªã±ãŒã·ã§ã³ãæžã
ç§ãã¡ã¯ããã¬ã€ã®éçšã§ç§ãã¡ã®ããã«æ°ããããšãç¥ããŸãã éå§ããã«ã¯ã 1-startãã©ã³ãã®ã¯ããŒã³ãäœæããããã³ãŒãå
ã§ã³ãŒããšåæããŸãã
ç§ãã¡ãæã£ãŠãããã¹ãŠã®åå¿åã¹ã¯ãªãããã¡ã€ã«ã«ã¯ãæ¡åŒµå.tsxããããŸãã
éå§ãã³ãã¬ãŒãã®äœãé¢çœãã§ããïŒ
- pre-commit hookïŒããã«ã€ããŠã¯ãã§ã«èª¬æããŸããïŒ text ã video ïŒ
- 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 }

OKãæšæºã¹ã¿ãŒãã <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ã«ãŒã«ãããã¯ãã§ãïŒ
ãšã©ãŒããã¹ãã®ç¿»èš³ãããããããã£ãanyåã§ãã£ãŠã¯ãªããªããšæšæž¬ããŠããŸãã ãã®ã¿ã€ãã¯ãäœã§ãããšç¿»èš³ã§ããŸãã ãã®ã¿ã€ãã®æé»çãªåºåãçŠæ¢ããã«ãŒã«ããããžã§ã¯ãã«ãããŸãã
-æé»çãªåæšè«ïŒ
-ãŸãã«ïŒ TypeScriptã¯ããã©ã«ãã§å€æ°ã®åãæšæž¬ããããšãã§ããããã«ããŸã察åŠããŸãã ããã¯åæšè«ãšåŒã°ããŸãã
äŸïŒ
let x = 3
props
ã®å Žå-TSã¯å€æ°ã®åã100ïŒ
決å®ã§ããªããããããã-
ïŒã€ãŸãã any
ïŒãšèšããŸãã ããã¯æé»çã«è¡ããããããžã§ã¯ãèšå®ïŒtsconfig.jsonïŒã®noImplicitAnyã«ãŒã«ã«ãã£ãŠçŠæ¢ãããŠããŸã
ã¿ã€ãanyãæç€ºçã«æå®ãããšããšã©ãŒãæ¶ããŸãã 倿°ã®ã¿ã€ãã¯ã³ãã³ã§ç€ºãããŸãã
å®äºããšã©ãŒã¯ãããŸããããããžã§ã¯ãã¯åäœããŸããã props
ãäœãã§ããå Žåããã®ãããªã¿ã€ãã³ã°ã®äœ¿çšã¯äœã§ããïŒ ååã
ããããšã¯ç¢ºãã§ãã ã«ãŒã«ã¯æ¬¡ã®ãšããã§ãã
ã¿ã€ããé¿ããããã«ããŠãã ãã
å¿
èŠãªå Žåany
ãããããã¯æ£åžžã§ãããå³å¯ãªã¿ã€ãã³ã°ã«ããããã«ãã«ãã®äžã«ææãäžããŸãã
props
çš®é¡ã説æããã«ã¯ã interface
ããŒã¯ãŒãã䜿çšãinterface
ã
name
ã¿ã€ããnumber
倿Žãããšãããã«ãšã©ãŒãçºçããŸãã

ããã«ãVS CodeïŒããã³ä»ã®å€ãã®ãšãã£ã¿ãŒïŒã§ããšã©ãŒã匷調ãããŸãã ãã®ãšã©ãŒã¯ãäžèŽãããã®ããªãããšã瀺ããŠããŸããæååãæž¡ããŸãããæ°åãå¿
èŠã§ãã
ãããprops
ãå¥ã®props
-ãµã€ãã<App />
远å ã<App />
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
IAppProps
åã«ã¯site
ããããã£ãååšããŸããã ããã§ãç§ã¯ããã«ãååã«ãã£ãŠã©ããèŠãã°ããã«ããããšèšããããšæããŸãã ãããã£ãŠãã¿ã€ãã«æ£ããååãä»ããŠãã ããã
ä¿®æ£ããåã«ããããããŸãããprops.site
ãprops.site
段èœãåé€props.site
ã
å¥ã®ãšã©ãŒããã¹ãã衚瀺ãããŸãã

ããã§ã¯ãTSãæšæž¬ãããã®ã®ã¿ã«æ³šç®ããããšæããŸãïŒ site
ã¯string
äžçš®ã§ãïŒã¹ã¯ãªãŒã³ã·ã§ããã§ã¯äžç·ãåŒãããŠããŸãïŒã
ä¿®æ£ïŒ
interface IAppProps { name: string; site: string;
ééããåé¡ããããŸããã
ã«ãŒãã£ã³ã°ã䜿çšããã«ã¯ãåãã¬ã³ããªã³ã°ããå¿
èŠããããŸãã èªåããå
ã«é²ã¿ããåã³ã³ããŒãã³ãããæç»ããŠã¿ãŸãããã
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> ) }
TSã¯èªãã圌ãã¯ããèšããããchildren
IAppProps
èšèŒããchildren
ããŸããã

ãã¡ãããç§ãã¡ã¯ããã€ãã®æšæºçãªãã®ããã¿ã€ãããããã¯ãããŸãããããã§ã¯ã³ãã¥ããã£ãå©ãã«ãªããŸãã ããšãã°ã @ types / reactããã±ãŒãžã«ã¯ãreactã®ãã¹ãŠã®å
¥åãå«ãŸããŠããŸãã
ãã®ããã±ãŒãžãã€ã³ã¹ããŒã«ããããšã§ïŒç§ã®äŸã§ã¯ãæ¢ã«ã€ã³ã¹ããŒã«ãããŠããŸãïŒã次ã®ãšã³ããªã䜿çšã§ããŸãã
React.FunctionComponent<P> React.FC<P>
ããã§ã <P>
ã¯props
ã®ã¿ã€ãã§ããã€ãŸããã¬ã³ãŒãã¯æ¬¡ã®åœ¢åŒãåããŸãã
React.FC<IAppProps>
倧éã®ããã¹ããèªãã®ã奜ããªäººã®ããã«ãç·Žç¿ããåã«ãã ãžã§ããªã㯠ãã«é¢ããèšäºãæäŸã§ããŸãïŒåã<and>ïŒã æ®ãã®éšåã«ã€ããŠã¯ãä»ã®ãšãããæ¬¡ã®ããã«ãã®ãã¬ãŒãºã翻蚳ããã ãã§ååã§ãã<such-and-such properties>ãåãå
¥ããæ©èœã³ã³ããŒãã³ãã
Appã³ã³ããŒãã³ãã®ãšã³ããªã¯å°ã倿ŽãããŸãã ãã«ããŒãžã§ã³ã
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
åŸã«-ã远å ãããããã
App倿°ã®ã¿ã€ãã¯React.FC<IAppProps>
ãªãããšãèšé²ããŸããã
React.FC
ã¯ã颿°ãã®ã¿ã€ãã§ããã<>å
ã§ãåŒæ°ã®ã¿ã€ãã瀺ããŸãããã€ãŸãã props
ã®ã¿ã€ããIAppProps
ããšãIAppProps
ã
ïŒç§ã¯ããªãã«å°ãåãã€ãããšãããªã¹ã¯ããããŸãããäŸãåçŽåããããã«ãããã¯å€§äžå€«ã ãšæããŸãïŒ
åèšïŒ Reactã³ã³ããŒãã³ãã®ããããã®ãããããã£ã倱ããã«ãéä¿¡ãããprops
ããããã£ã®ã¿ã€ããæå®ããããšãåŠã³ãŸããã
çŸåšã®ãœãŒã¹ã³ãŒã ã
ã«ãŒãã£ã³ã°ã远å
ãªãŒãã«ãŒã¿ãŒã䜿çšããŠèŠéãåºããŸãã ãã®ããã±ãŒãžã¯ãreact-routerã«éåžžã«äŒŒãŠããŸãã
ããŒãžã远å ãã-ãã¥ãŒã¹ã <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'
ã¢ããªã±ãŒã·ã§ã³ãå£ããããšã©ãŒïŒç«¯æ«ã«æåã®ãšã©ãŒã衚瀺ãããããããšã©ãŒã®1ã€ïŒïŒ

ãã§ã«ãã®ã¬ã³ãŒãã«å°ãæ
£ããŠãpath
ãã <App />
åã®èª¬æã«ã¯path
ãååšããªãããšãããããŸãã
ç¹°ãè¿ããŸããããã¹ãŠã¯ç§ãã¡ã®åã«èšè¿°ãããŠããŸãã @ types / reach__routerããã±ãŒãžãšRouteComponentProps
ã¿ã€ãã䜿çšããŸãã ããããã£ã倱ããªãããã«ã extends
ã䜿çšãextends
ã
import * as React from 'react'
奜å¥å¿For çãªäººã®ããã«ã RouteComponentPropsã§ã©ã®ã¿ã€ãã説æãããŠããŸããã
<App />
ã®ãšã©ãŒã¯æ¶ããŸãããããã®ã³ã³ããŒãã³ãã®å
¥åãæå®ããªãã£ãããã <News />
æ®ããŸããã
ããã¿ã¹ã¯ïŒ <News />
å
¥åãæå®ããŸãã çŸæç¹ã§ã¯ãã«ãŒã¿ãŒããã®ããããã£ã®ã¿ãããã«è»¢éãããŸãã
çãã¯ïŒ
src / Pages / News.tsx
import * as React from 'react' import { RouteComponentProps } from '@reach/router'

次ã«ããã©ã¡ãŒã¿ã䜿çšããŠã«ãŒãã远å ããŸãã reach-routerã®ãã©ã¡ãŒã¿ãŒã¯ ãå°éå
·ã«çŽæ¥äœãã§ããŸãã åå¿ããã«ãŒã¿ãŒã§ã¯ãèŠããŠããããã«ã props.match
ã«äœãã§ã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'
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 }
äºæããŠããªãã£ããšã©ãŒïŒ

sourceããããã£ã¯ååšããŸãã...äžæ¹ãæžæãïŒæååã§ãããã¹ã«æž¡ããŸãã仿¹ãåã³ïŒãããã©ã€ãã©ãªã®äœæè
ãšå
¥åè
ã¯ã©ã®ããã«ããŠãã®èŠåã远å ããããšããŸãããã
ãããä¿®æ£ããã«ã¯ã RouteComponentProps
ãããªãã·ã§ã³ãæ¡åŒµïŒæ¡åŒµïŒãããªãã·ã§ã³ã®source
ããããã£ãæå®ããŸãã ãªãã·ã§ã³ãURLã«å«ãŸããŠããªãå¯èœæ§ãããããã
TypeScriptã¯ãçå笊ã䜿çšããŠãªãã·ã§ã³ã®ããããã£ã瀺ããŸãã
src / pages / About.tsx
import * as React from 'react' import { RouteComponentProps } from '@reach/router' interface IAboutProps extends RouteComponentProps { source?: string;
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 / models / news.ts ïŒæ¡åŒµå.ts ïŒ
export interface INewsItem { id: number; title: string; text: string; link: string; timestamp: Date; }
æ°ãã1ã€ã®ã¿ã€ã ã¹ã¿ã³ããã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,
api getNews
ããã®åŒã³åºãã¯Promiseãè¿ãããã®ãPromiseãã«ã¯ç¹å®ã®ã¿ã€ãããããããã«ã€ããŠã説æã§ããŸãã
interface INewsResponse { status: number;
æãïŒ Promiseã¿ã€ãã¯ãžã§ããªãã¯ã§ãããããããã«æããªããŸããåã³<
ãš>
ãåŠçããå¿
èŠããã>
ã ããã¯ãã¥ãŒããªã¢ã«ã®æãé£ããéšåãªã®ã§ãæçµã³ãŒããèªã¿ãŸãã
src / api / News.ts
import { INewsItem } from '../models/news'
ç
çªã
ãã¥ãŒã¹ã衚瀺
src / pages / News.tsx
import * as React from 'react' import { RouteComponentProps } from '@reach/router' import { getNews } from '../api/news' import { NewsItem } from '../components/NewsItem'
ã³ãŒãã¯ãTypeScriptã«é¢é£ããã³ã¡ã³ããæäŸããŸãã åå¿ããã¯ã«é¢ãããã«ããå¿
èŠãªå Žåã¯ã ããã¥ã¡ã³ã ïŒENïŒã ãã¥ãŒããªã¢ã« ïŒRUïŒãåç
§ããŠãã ããã
ã¿ã¹ã¯ïŒãã¥ãŒã¹ã衚瀺ãã<NewsItem />
ã³ã³ããŒãã³ããäœæããŸãã å¿
ãæ£ããã¿ã€ããæå®ããŠãã ããã INewsItem
ã¢ãã«ã䜿çšããŸãã
çµæã¯æ¬¡ã®ããã«ãªããŸãã

解決çã¯æ¬¡ã®ãšããã§ãã
src / components / NewsItem.tsx
import * as React from 'react' import { INewsItem } from '../models/news' interface INewsItemProps { data: INewsItem;
åé¡ã¯ãã€ã³ã¿ãŒãã§ã€ã¹ããã®ããã«èšè¿°ããçç±ã§ãïŒã³ãŒã[1]ããã³[2]ã®ã³ã¡ã³ãïŒã ãã æžãããšãã§ããŸãïŒ
React.FC<INewsItem>
çãã¯ä»¥äžã§ãã
ã
ã
ã
data
ããããã£ã§ãã¥ãŒã¹ãæž¡ãã®ã§ã次ã®ããã«èšè¿°ããå¿
èŠããããŸãã
React.FC<{ data: INewsItem }>
ä»ã®ããããã£ãã³ã³ããŒãã³ãã«è¿œå ãããå Žåã«ã interface
ãæå®ãããšããéããããã ãã§ãã ãããŠèªã¿ããããåäžããŸãã
åèšïŒ Promiseããã³useEffectã®ã¿ã€ãã³ã°ãç·Žç¿ããŸããã å¥ã®ã³ã³ããŒãã³ãã®ã¿ã€ãã説æããŸããã
ãŸã TSã®èªå眮æãšå³å¯ãã«æãããããªãå Žåã¯ãç·Žç¿ããªãããå³å¯ãªã¿ã€ãã³ã°ã¯ããªãã®ããã§ã¯ãããŸããã 2çªç®ã®å Žå-ç§ã¯äœãæäŒãããšãã§ããŸãããããã¯å¥œã¿ã®åé¡ã§ãã åžå Žããã®æ¡ä»¶ã決å®ããTypeScriptã䜿çšããªãå Žåã¯flowã䜿çšããŠãããå€ãã®ãããžã§ã¯ããã¿ã€ãã³ã°ã䜿çšããŠå®è¡ããããšããäºå®ã«æ³šç®ããŸãã
çŸåšã®ãœãŒã¹ã³ãŒã ã
èªèšŒAPI
ãã°ã€ã³çšã®api
ãäœæããŸãã ååã¯äŒŒãŠããŸã-æ¿èªæžã¿/ãšã©ãŒã®ããpromise
ãè¿ããŸãã æ¿èªã¹ããŒã¿ã¹ã«é¢ããæ
å ±ãlocalStorage
ä¿åãlocalStorage
ïŒ å€ãã®äººã¯ãããã»ãã¥ãªãã£ã®é倧ãªéåã ãšèããŠããŸããç§ã¯çŽäºã«å°ãé
ããŠãããã©ã®ããã«çµäºãããããããŸãã ïŒã
ãã®ã¢ããªã±ãŒã·ã§ã³ã§ã¯ããã°ã€ã³ã¯ãŠãŒã¶ãŒåãšãã¹ã¯ãŒãã®æïŒäž¡æ¹ãšãæååïŒã§ãããããã¢ãã«ã«ã€ããŠèª¬æããŸãã
src / models / user.ts
export interface IUserIdentity { username: string; password: string; }
src / api / auth.ts
import { navigate } from '@reach/router' import { IUserIdentity } from '../models/user'
, .
:
: . 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'
, 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'
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'
, .

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 .