2019-02-04 21:56:24 +02:00
# clean - code - typescript [ ! [ Tweet ] ( https : //img.shields.io/twitter/url/http/shields.io.svg?style=social)](https://twitter.com/intent/tweet?text=Clean%20Code%20Typescript&url=https://github.com/labs42io/clean-code-typescript)
2019-01-26 10:52:23 +02:00
2025-05-01 11:11:48 +02:00
К о н ц е п ц і ї Clean Code , а д а п т о в а н і д л я TypeScript .
Н а т х н е н н і [ clean - code - javascript ] ( https : //github.com/ryanmcdermott/clean-code-javascript).
2019-01-26 10:52:23 +02:00
2025-05-01 11:11:48 +02:00
# # З м і с т
2019-01-29 09:44:59 +02:00
2025-05-01 11:11:48 +02:00
1 . [ В с т у п ] ( # в с т у п )
2 . [ З м і н н і ] ( # з м і н н і )
3 . [ Ф у н к ц і ї ] ( # ф у н к ц і ї )
4 . [ О б ' є к т и т а с т р у к т у р и д а н и х ] ( # о б є к т и - т а - с т р у к т у р и - д а н и х )
5 . [ К л а с и ] ( # к л а с и )
2019-02-04 18:08:52 +02:00
6 . [ SOLID ] ( # solid )
2025-05-01 11:11:48 +02:00
7 . [ Т е с т у в а н н я ] ( # т е с т у в а н н я )
8 . [ П а р а л е л ь н і с т ь ] ( # п а р а л е л ь н і с т ь )
9 . [ О б р о б к а п о м и л о к ] ( # о б р о б к а - п о м и л о к )
10 . [ Ф о р м а т у в а н н я ] ( # ф о р м а т у в а н н я )
11 . [ К о м е н т а р і ] ( # к о м е н т а р і )
12 . [ П е р е к л а д и ] ( # п е р е к л а д и )
2019-01-26 10:52:23 +02:00
2025-05-01 11:11:48 +02:00
# # В с т у п
2019-01-29 09:44:59 +02:00
2025-05-01 11:11:48 +02:00
! [ Г у м о р и с т и ч н е з о б р а ж е н н я о ц і н к и я к о с т і п р о г р а м н о г о з а б е з п е ч е н н я я к к і л ь к о с т і л а й л и в и х с л і в , я к і в и в и г у к у є т е , к о л и ч и т а є т е к о д ] ( https : //www.osnews.com/images/comics/wtfm.jpg)
2019-01-26 10:52:23 +02:00
2025-05-01 11:11:48 +02:00
П р и н ц и п и п р о г р а м н о ї і н ж е н е р і ї з к н и г и Р о б е р т а К . М а р т і н а [ * Clean Code * ] ( https : //www.amazon.com/Clean-Code-Handbook-Software-Craftsmanship/dp/0132350882), адаптовані для TypeScript. Це не стильовий посібник. Це посібник з написання [читабельного, повторно використовуваного та рефакторингового](https://github.com/ryanmcdermott/3rs-of-software-architecture) програмного забезпечення на TypeScript.
2019-01-26 10:52:23 +02:00
2025-05-01 11:11:48 +02:00
Н е к о ж е н п р и н ц и п т у т п о в и н е н с у в о р о д о т р и м у в а т и с ь , і щ е м е н ш е з н и х б у д у т ь з а г а л ь н о п р и й н я т и м и . Ц е л и ш е р е к о м е н д а ц і ї , і н і ч о г о б і л ь ш е , а л е в о н и к о д и ф і к о в а н і б а г а т о р і ч н и м к о л е к т и в н и м д о с в і д о м а в т о р і в к н и г и * Clean Code * .
2019-01-26 10:52:23 +02:00
2025-05-01 11:11:48 +02:00
Н а ш е р е м е с л о п р о г р а м н о ї і н ж е н е р і ї н а л і ч у є л и ш е т р о х и б і л ь ш е 50 р о к і в , і м и в с е щ е б а г а т о ч о г о в ч и м о с я . К о л и а р х і т е к т у р а п р о г р а м н о г о з а б е з п е ч е н н я с т а н е т а к о ю ж с т а р о ю , я к а р х і т е к т у р а б у д і в е л ь , м о ж л и в о , т о д і у н а с б у д у т ь ж о р с т к і ш і п р а в и л а д л я д о т р и м а н н я . А п о к и щ о , н е х а й ц і р е к о м е н д а ц і ї с л у г у ю т ь о р і є н т и р о м д л я о ц і н к и я к о с т і к о д у TypeScript , я к и й с т в о р ю є т е в и т а в а ш а к о м а н д а .
2019-01-26 10:52:23 +02:00
2025-05-01 11:11:48 +02:00
Щ е о д н а річ : знання ц и х п р и н ц и п і в н е з р о б и т ь в а с м и т т є в о к р а щ и м р о з р о б н и к о м п р о г р а м н о г о з а б е з п е ч е н н я , і р о б о т а з н и м и п р о т я г о м б а г а т ь о х р о к і в н е о з н а ч а є , щ о в и н е б у д е т е п о м и л я т и с я . К о ж е н ф р а г м е н т к о д у п о ч и н а є т ь с я я к п е р ш и й ч е р н е т к о в и й в а р і а н т , я к м о к р а г л и н а , щ о н а б у в а є с в о є ї о с т а т о ч н о ї ф о р м и . В р е ш т і - р е ш т , м и в и р і з а є м о н е д о л і к и , к о л и п е р е г л я д а є м о к о д з к о л е г а м и . Н е к а р т а й т е с е б е з а п е р ш і ч е р н е т к и , я к і п о т р е б у ю т ь п о к р а щ е н н я . Н а т о м і с т ь к р и т и к у й т е с а м к о д !
2019-01-26 10:52:23 +02:00
2025-05-01 11:13:28 +02:00
* * [ ⬆ п о в е р н у т и с я д о з м і с т у ] ( # з м і с т ) * *
2019-01-28 17:55:17 +02:00
2025-05-01 11:11:48 +02:00
# # З м і н н і
2019-01-28 17:55:17 +02:00
2025-05-01 11:11:48 +02:00
# # # В и к о р и с т о в у й т е з м і с т о в н і і м е н а з м і н н и х
2019-01-28 17:55:17 +02:00
2025-05-01 11:11:48 +02:00
Р о з р і з н я й т е і м е н а т а к и м ч и н о м , щ о б ч и т а ч р о з у м і в , я к і м і ж н и м и в і д м і н н о с т і .
2019-01-28 17:55:17 +02:00
2025-05-01 11:11:48 +02:00
* * П о г а н о : * *
2019-01-28 17:55:17 +02:00
` ` ` ts
2019-02-06 09:57:52 +02:00
function between < T > ( a1 : T , a2 : T , a3 : T ) : boolean {
2019-01-28 17:55:17 +02:00
return a2 <= a1 && a1 <= a3 ;
}
` ` `
2025-05-01 11:11:48 +02:00
* * Д о б р е : * *
2019-01-28 17:55:17 +02:00
` ` ` ts
2019-02-06 09:57:52 +02:00
function between < T > ( value : T , left : T , right : T ) : boolean {
2019-01-28 17:55:17 +02:00
return left <= value && value <= right ;
}
` ` `
2025-05-01 11:13:28 +02:00
* * [ ⬆ п о в е р н у т и с я д о з м і с т у ] ( # з м і с т ) * *
2019-01-28 17:55:17 +02:00
2025-05-01 11:11:48 +02:00
# # # В и к о р и с т о в у й т е в и м о в н і і м е н а з м і н н и х
2019-01-28 17:55:17 +02:00
2025-05-01 11:11:48 +02:00
Я к щ о в и н е м о ж е т е в и м о в и т и і м ' я з м і н н о ї , в и н е з м о ж е т е о б г о в о р ю в а т и ї ї , н е з в у ч а ч и я к і д і о т .
2019-01-28 17:55:17 +02:00
2025-05-01 11:11:48 +02:00
* * П о г а н о : * *
2019-01-28 17:55:17 +02:00
` ` ` ts
2019-02-06 09:57:52 +02:00
type DtaRcrd102 = {
genymdhms : Date ;
modymdhms : Date ;
pszqint : number ;
2019-01-28 17:55:17 +02:00
}
` ` `
2025-05-01 11:11:48 +02:00
* * Д о б р е : * *
2019-01-28 17:55:17 +02:00
` ` ` ts
2019-02-06 09:57:52 +02:00
type Customer = {
generationTimestamp : Date ;
modificationTimestamp : Date ;
recordId : number ;
2019-01-28 17:55:17 +02:00
}
` ` `
2025-05-01 11:13:28 +02:00
* * [ ⬆ п о в е р н у т и с я д о з м і с т у ] ( # з м і с т ) * *
2019-02-04 18:18:27 +02:00
2025-05-01 11:11:48 +02:00
# # # В и к о р и с т о в у й т е о д н а к о в и й с л о в н и к о в и й з а п а с д л я о д н а к о в о г о т и п у з м і н н и х
2019-01-28 17:55:17 +02:00
2025-05-01 11:11:48 +02:00
* * П о г а н о : * *
2019-01-28 17:55:17 +02:00
` ` ` ts
function getUserInfo ( ) : User ;
function getUserDetails ( ) : User ;
function getUserData ( ) : User ;
` ` `
2025-05-01 11:11:48 +02:00
* * Д о б р е : * *
2019-01-28 17:55:17 +02:00
` ` ` ts
function getUser ( ) : User ;
` ` `
2025-05-01 11:13:28 +02:00
* * [ ⬆ п о в е р н у т и с я д о з м і с т у ] ( # з м і с т ) * *
2019-01-28 17:55:17 +02:00
2025-05-01 11:11:48 +02:00
# # # В и к о р и с т о в у й т е п о ш у к о в і і м е н а
2019-01-28 17:55:17 +02:00
2025-05-01 11:11:48 +02:00
М и б у д е м о ч и т а т и б і л ь ш е к о д у , н і ж к о л и - н е б у д ь н а п и ш е м о . В а ж л и в о , щ о б к о д , я к и й м и п и ш е м о , б у в ч и т а б е л ь н и м і п о ш у к о в и м . Н е н а з и в а ю ч и з м і н н і і м е н а м и , я к і м а ю т ь з н а ч е н н я д л я р о з у м і н н я н а ш о ї п р о г р а м и , м и ш к о д и м о н а ш и м ч и т а ч а м . Р о б і т ь в а ш і і м е н а п о ш у к о в и м и . І н с т р у м е н т и , т а к і я к [ ESLint ] ( https : //typescript-eslint.io/), можуть допомогти ідентифікувати неназвані константи (також відомі як магічні рядки та магічні числа).
2019-01-28 17:55:17 +02:00
2025-05-01 11:11:48 +02:00
* * П о г а н о : * *
2019-01-28 17:55:17 +02:00
` ` ` ts
2025-05-01 11:11:48 +02:00
// Що за чорт, для чого ці 86400000?
2019-01-28 17:55:17 +02:00
setTimeout ( restart , 86400000 ) ;
` ` `
2025-05-01 11:11:48 +02:00
* * Д о б р е : * *
2019-01-28 17:55:17 +02:00
` ` ` ts
2025-05-01 11:11:48 +02:00
// Оголосіть їх як капіталізовані іменовані константи.
2022-04-26 09:58:56 +03:00
const MILLISECONDS_PER_DAY = 24 * 60 * 60 * 1000 ; // 86400000
2019-01-28 17:55:17 +02:00
2022-04-26 09:58:56 +03:00
setTimeout ( restart , MILLISECONDS_PER_DAY ) ;
2019-01-28 17:55:17 +02:00
` ` `
2025-05-01 11:13:28 +02:00
* * [ ⬆ п о в е р н у т и с я д о з м і с т у ] ( # з м і с т ) * *
2019-01-28 17:55:17 +02:00
2025-05-01 11:11:48 +02:00
# # # В и к о р и с т о в у й т е п о я с н ю в а л ь н і з м і н н і
2019-01-28 17:55:17 +02:00
2025-05-01 11:11:48 +02:00
* * П о г а н о : * *
2019-01-28 17:55:17 +02:00
` ` ` ts
2019-02-06 09:57:52 +02:00
declare const users : Map < string , User > ;
2019-01-28 17:55:17 +02:00
for ( const keyValue of users ) {
2025-05-01 11:11:48 +02:00
// ітерація по мапі користувачів
2019-01-28 17:55:17 +02:00
}
` ` `
2025-05-01 11:11:48 +02:00
* * Д о б р е : * *
2019-01-28 17:55:17 +02:00
` ` ` ts
2019-02-06 09:57:52 +02:00
declare const users : Map < string , User > ;
2019-01-28 17:55:17 +02:00
for ( const [ id , user ] of users ) {
2025-05-01 11:11:48 +02:00
// ітерація по мапі користувачів
2019-01-28 17:55:17 +02:00
}
` ` `
2025-05-01 11:13:28 +02:00
* * [ ⬆ п о в е р н у т и с я д о з м і с т у ] ( # з м і с т ) * *
2019-01-28 17:55:17 +02:00
2025-05-01 11:11:48 +02:00
# # # У н и к а й т е м е н т а л ь н о г о к а р т у в а н н я
2019-01-28 17:55:17 +02:00
2025-05-01 11:11:48 +02:00
Я в н е к р а щ е , н і ж н е я в н е .
* Ч і т к і с т ь - ц е к о р о л ь . *
2019-01-28 17:55:17 +02:00
2025-05-01 11:11:48 +02:00
* * П о г а н о : * *
2019-01-28 17:55:17 +02:00
` ` ` ts
const u = getUser ( ) ;
const s = getSubscription ( ) ;
const t = charge ( u , s ) ;
` ` `
2025-05-01 11:11:48 +02:00
* * Д о б р е : * *
2019-01-28 17:55:17 +02:00
` ` ` ts
const user = getUser ( ) ;
const subscription = getSubscription ( ) ;
const transaction = charge ( user , subscription ) ;
` ` `
2025-05-01 11:13:28 +02:00
* * [ ⬆ п о в е р н у т и с я д о з м і с т у ] ( # з м і с т ) * *
2019-01-28 17:55:17 +02:00
2025-05-01 11:11:48 +02:00
# # # Н е д о д а в а й т е н е п о т р і б н и й к о н т е к с т
2019-01-28 17:55:17 +02:00
2025-05-01 11:11:48 +02:00
Я к щ о і м 'я вашого класу/типу/о б ' є к т а г о в о р и т ь в а м щ о с ь , н е п о в т о р ю й т е ц е в і м е н і з м і н н о ї .
2019-01-28 17:55:17 +02:00
2025-05-01 11:11:48 +02:00
* * П о г а н о : * *
2019-01-28 17:55:17 +02:00
` ` ` ts
2019-02-05 14:22:02 +02:00
type Car = {
2019-01-28 17:55:17 +02:00
carMake : string ;
carModel : string ;
carColor : string ;
2019-02-05 14:22:02 +02:00
}
2019-01-28 17:55:17 +02:00
2019-02-05 14:22:02 +02:00
function print ( car : Car ) : void {
2019-02-06 13:05:25 +09:00
console . log ( ` ${ car . carMake } ${ car . carModel } ( ${ car . carColor } ) ` ) ;
2019-01-28 17:55:17 +02:00
}
` ` `
2025-05-01 11:11:48 +02:00
* * Д о б р е : * *
2019-01-28 17:55:17 +02:00
` ` ` ts
2019-02-05 14:22:02 +02:00
type Car = {
2019-01-28 17:55:17 +02:00
make : string ;
model : string ;
color : string ;
2019-02-05 14:22:02 +02:00
}
2019-01-28 17:55:17 +02:00
2019-02-05 14:22:02 +02:00
function print ( car : Car ) : void {
2019-02-06 13:05:25 +09:00
console . log ( ` ${ car . make } ${ car . model } ( ${ car . color } ) ` ) ;
2019-01-28 17:55:17 +02:00
}
` ` `
2025-05-01 11:13:28 +02:00
* * [ ⬆ п о в е р н у т и с я д о з м і с т у ] ( # з м і с т ) * *
2019-01-28 17:55:17 +02:00
2025-05-01 11:11:48 +02:00
# # # В и к о р и с т о в у й т е а р г у м е н т и з а з а м о в ч у в а н н я м з а м і с т ь к о р о т к о г о з а ц и к л е н н я а б о у м о в
2019-01-28 17:55:17 +02:00
2025-05-01 11:11:48 +02:00
А р г у м е н т и з а з а м о в ч у в а н н я м ч а с т о ч и с т і ш і , н і ж к о р о т к е з а ц и к л е н н я .
2019-01-28 17:55:17 +02:00
2025-05-01 11:11:48 +02:00
* * П о г а н о : * *
2019-01-28 17:55:17 +02:00
` ` ` ts
2019-02-05 17:21:31 +02:00
function loadPages ( count? : number ) {
2019-02-05 14:22:02 +02:00
const loadCount = count !== undefined ? count : 10 ;
// ...
2019-01-28 17:55:17 +02:00
}
` ` `
2025-05-01 11:11:48 +02:00
* * Д о б р е : * *
2019-01-28 17:55:17 +02:00
` ` ` ts
function loadPages ( count : number = 10 ) {
2019-02-05 14:22:02 +02:00
// ...
2019-01-28 17:55:17 +02:00
}
` ` `
2025-05-01 11:13:28 +02:00
* * [ ⬆ п о в е р н у т и с я д о з м і с т у ] ( # з м і с т ) * *
2019-01-28 17:56:21 +02:00
2025-05-01 11:11:48 +02:00
# # # В и к о р и с т о в у й т е enum д л я д о к у м е н т у в а н н я н а м і р у
2019-05-30 14:02:11 +02:00
2025-05-01 11:11:48 +02:00
П е р е р а х у в а н н я ( enums ) м о ж у т ь д о п о м о г т и в а м д о к у м е н т у в а т и н а м і р к о д у . Н а п р и к л а д , к о л и м и б і л ь ш е т у р б у є м о с я п р о т е , щ о б з н а ч е н н я в і д р і з н я л и с ь , н і ж п р о ї х т о ч н е з н а ч е н н я .
2019-05-30 14:02:11 +02:00
2025-05-01 11:11:48 +02:00
* * П о г а н о : * *
2019-05-30 14:02:11 +02:00
` ` ` ts
const GENRE = {
ROMANTIC : 'romantic' ,
DRAMA : 'drama' ,
COMEDY : 'comedy' ,
DOCUMENTARY : 'documentary' ,
}
projector . configureFilm ( GENRE . COMEDY ) ;
class Projector {
2025-05-01 11:11:48 +02:00
// декларація Projector
2019-05-30 14:02:11 +02:00
configureFilm ( genre ) {
switch ( genre ) {
case GENRE . ROMANTIC :
2025-05-01 11:11:48 +02:00
// якась логіка для виконання
2019-05-30 14:02:11 +02:00
}
}
}
` ` `
2025-05-01 11:11:48 +02:00
* * Д о б р е : * *
2019-05-30 14:02:11 +02:00
` ` ` ts
enum GENRE {
ROMANTIC ,
DRAMA ,
COMEDY ,
DOCUMENTARY ,
}
projector . configureFilm ( GENRE . COMEDY ) ;
class Projector {
2025-05-01 11:11:48 +02:00
// декларація Projector
2019-05-30 14:02:11 +02:00
configureFilm ( genre ) {
switch ( genre ) {
case GENRE . ROMANTIC :
2025-05-01 11:11:48 +02:00
// якась логіка для виконання
2019-05-30 14:02:11 +02:00
}
}
}
` ` `
2025-05-01 11:13:28 +02:00
* * [ ⬆ п о в е р н у т и с я д о з м і с т у ] ( # з м і с т ) * *
2019-05-30 14:02:11 +02:00
2025-05-01 11:11:48 +02:00
# # Ф у н к ц і ї
2019-01-31 10:18:41 +02:00
2025-05-01 11:11:48 +02:00
# # # А р г у м е н т и ф у н к ц і й ( в і д е а л і 2 а б о м е н ш е )
2019-01-31 10:18:41 +02:00
2025-05-01 11:11:48 +02:00
О б м е ж е н н я к і л ь к о с т і п а р а м е т р і в ф у н к ц і ї н е й м о в і р н о в а ж л и в е , о с к і л ь к и ц е п о л е г ш у є т е с т у в а н н я в а ш о ї ф у н к ц і ї .
Н а я в н і с т ь б і л ь ш е т р ь о х п р и з в о д и т ь д о к о м б і н а т о р н о г о в и б у х у , к о л и в и п о в и н н і т е с т у в а т и т о н н и р і з н и х в и п а д к і в д л я к о ж н о г о о к р е м о г о а р г у м е н т у .
2019-01-31 10:18:41 +02:00
2025-05-01 11:11:48 +02:00
О д и н а б о д в а а р г у м е н т и - ц е і д е а л ь н и й в и п а д о к , а т р ь о х с л і д у н и к а т и , я к щ о ц е м о ж л и в о . В с е , щ о п е р е в и щ у є ц е , м а є б у т и к о н с о л і д о в а н о .
З а з в и ч а й , я к щ о у в а с б і л ь ш е д в о х а р г у м е н т і в , т о в а ш а ф у н к ц і я н а м а г а є т ь с я з р о б и т и з а н а д т о б а г а т о .
У в и п а д к а х , к о л и ц е н е т а к , з д е б і л ь ш о г о о б ' є к т в и щ о г о р і в н я б у д е д о с т а т н і м я к а р г у м е н т .
2019-01-31 10:18:41 +02:00
2025-05-01 11:11:48 +02:00
Р о з г л я н ь т е м о ж л и в і с т ь в и к о р и с т а н н я о б ' є к т н и х л і т е р а л і в , я к щ о в а м п о т р і б н о б а г а т о а р г у м е н т і в .
2019-01-31 10:18:41 +02:00
2025-05-01 11:11:48 +02:00
Щ о б б у л о о ч е в и д н о , я к і в л а с т и в о с т і о ч і к у є ф у н к ц і я , в и м о ж е т е в и к о р и с т о в у в а т и с и н т а к с и с [ д е с т р у к т у р и з а ц і ї ] ( https : //basarat.gitbook.io/typescript/future-javascript/destructuring).
Ц е м а є к і л ь к а п е р е в а г :
2019-01-31 10:18:41 +02:00
2025-05-01 11:11:48 +02:00
1 . К о л и х т о с ь д и в и т ь с я н а с и г н а т у р у ф у н к ц і ї , в і д р а з у з р о з у м і л о , я к і в л а с т и в о с т і в и к о р и с т о в у ю т ь с я .
2019-01-31 10:18:41 +02:00
2025-05-01 11:11:48 +02:00
2 . Ц е м о ж н а в и к о р и с т о в у в а т и д л я і м і т а ц і ї і м е н о в а н и х п а р а м е т р і в .
2019-01-31 10:18:41 +02:00
2025-05-01 11:11:48 +02:00
3 . Д е с т р у к т у р и з а ц і я т а к о ж к л о н у є в к а з а н і п р и м і т и в н і з н а ч е н н я о б 'єкта аргументу, переданого у функцію. Це може допомогти запобігти побічним ефектам. Примітка: о б ' є к т и т а м а с и в и , я к і д е с т р у к т у р и з у ю т ь с я з о б ' є к т а а р г у м е н т у , Н Е к л о н у ю т ь с я .
2020-01-31 19:01:53 +02:00
2025-05-01 11:11:48 +02:00
4 . TypeScript п о п е р е д ж а є п р о н е в и к о р и с т а н і в л а с т и в о с т і , щ о б у л о б н е м о ж л и в о б е з д е с т р у к т у р и з а ц і ї .
2019-01-31 10:18:41 +02:00
2025-05-01 11:11:48 +02:00
* * П о г а н о : * *
2019-01-31 10:18:41 +02:00
` ` ` ts
function createMenu ( title : string , body : string , buttonText : string , cancellable : boolean ) {
// ...
}
createMenu ( 'Foo' , 'Bar' , 'Baz' , true ) ;
` ` `
2025-05-01 11:11:48 +02:00
* * Д о б р е : * *
2019-01-31 10:18:41 +02:00
` ` ` ts
2019-02-06 09:57:52 +02:00
function createMenu ( options : { title : string , body : string , buttonText : string , cancellable : boolean } ) {
2019-01-31 10:18:41 +02:00
// ...
}
createMenu ( {
title : 'Foo' ,
body : 'Bar' ,
buttonText : 'Baz' ,
cancellable : true
} ) ;
` ` `
2025-05-01 11:11:48 +02:00
В и м о ж е т е щ е б і л ь ш е п о к р а щ и т и ч и т а б е л ь н і с т ь , в и к о р и с т о в у ю ч и [ а л і а с и т и п і в ] ( https : //www.typescriptlang.org/docs/handbook/advanced-types.html#type-aliases):
2019-01-31 10:18:41 +02:00
` ` ` ts
2019-02-06 09:57:52 +02:00
type MenuOptions = { title : string , body : string , buttonText : string , cancellable : boolean } ;
2019-01-31 10:18:41 +02:00
function createMenu ( options : MenuOptions ) {
// ...
}
createMenu ( {
title : 'Foo' ,
body : 'Bar' ,
buttonText : 'Baz' ,
cancellable : true
} ) ;
` ` `
2025-05-01 11:13:28 +02:00
* * [ ⬆ п о в е р н у т и с я д о з м і с т у ] ( # з м і с т ) * *
2019-01-31 10:18:41 +02:00
2025-05-01 11:11:48 +02:00
# # # Ф у н к ц і ї п о в и н н і р о б и т и о д н е
2019-01-31 10:18:41 +02:00
2025-05-01 11:11:48 +02:00
Ц е , б е з у м о в н о , н а й в а ж л и в і ш е п р а в и л о в п р о г р а м н і й і н ж е н е р і ї . К о л и ф у н к ц і ї р о б л я т ь б і л ь ш е , н і ж о д н е , ї х в а ж ч е с т в о р ю в а т и , т е с т у в а т и т а р о з у м і т и . К о л и в и м о ж е т е і з о л ю в а т и ф у н к ц і ю д о о д н і є ї д і ї , ї ї л е г к о р е ф а к т о р и т и , і в а ш к о д б у д е н а б а г а т о ч и с т і ш и м . Я к щ о в и н е в и н е с е т е з ц ь о г о п о с і б н и к а н і ч о г о і н ш о г о , к р і м ц ь о г о , в и в и п е р е д и т е б а г а т ь о х р о з р о б н и к і в .
2019-01-31 10:18:41 +02:00
2025-05-01 11:11:48 +02:00
* * П о г а н о : * *
2019-01-31 10:18:41 +02:00
` ` ` ts
2022-04-17 16:02:19 +01:00
function emailActiveClients ( clients : Client [ ] ) {
2019-01-31 10:18:41 +02:00
clients . forEach ( ( client ) = > {
const clientRecord = database . lookup ( client ) ;
if ( clientRecord . isActive ( ) ) {
email ( client ) ;
}
} ) ;
}
` ` `
2025-05-01 11:11:48 +02:00
* * Д о б р е : * *
2019-01-31 10:18:41 +02:00
` ` ` ts
2022-04-17 16:02:19 +01:00
function emailActiveClients ( clients : Client [ ] ) {
2019-01-31 10:18:41 +02:00
clients . filter ( isActiveClient ) . forEach ( email ) ;
}
function isActiveClient ( client : Client ) {
const clientRecord = database . lookup ( client ) ;
return clientRecord . isActive ( ) ;
}
` ` `
2025-05-01 11:13:28 +02:00
* * [ ⬆ п о в е р н у т и с я д о з м і с т у ] ( # з м і с т ) * *
2019-01-31 10:18:41 +02:00
2025-05-01 11:11:48 +02:00
# # # Н а з в и ф у н к ц і й п о в и н н і г о в о р и т и , щ о в о н и р о б л я т ь
2019-01-31 10:18:41 +02:00
2025-05-01 11:11:48 +02:00
* * П о г а н о : * *
2019-01-31 10:18:41 +02:00
` ` ` ts
function addToDate ( date : Date , month : number ) : Date {
// ...
}
const date = new Date ( ) ;
2025-05-01 11:11:48 +02:00
// Важко зрозуміти з назви функції, що саме додається
2019-01-31 10:18:41 +02:00
addToDate ( date , 1 ) ;
` ` `
2025-05-01 11:11:48 +02:00
* * Д о б р е : * *
2019-01-31 10:18:41 +02:00
` ` ` ts
function addMonthToDate ( date : Date , month : number ) : Date {
// ...
}
const date = new Date ( ) ;
addMonthToDate ( date , 1 ) ;
` ` `
2025-05-01 11:13:28 +02:00
* * [ ⬆ п о в е р н у т и с я д о з м і с т у ] ( # з м і с т ) * *
2019-01-31 10:18:41 +02:00
2025-05-01 11:11:48 +02:00
# # # Ф у н к ц і ї п о в и н н і б у т и л и ш е н а о д н о м у р і в н і а б с т р а к ц і ї
2019-01-31 10:18:41 +02:00
2025-05-01 11:11:48 +02:00
К о л и у в а с б і л ь ш е о д н о г о р і в н я а б с т р а к ц і ї , в а ш а ф у н к ц і я з а з в и ч а й р о б и т ь з а н а д т о б а г а т о . Р о з д і л е н н я ф у н к ц і й п р и з в о д и т ь д о п о в т о р н о г о в и к о р и с т а н н я т а п о л е г ш у є т е с т у в а н н я .
2019-01-31 10:18:41 +02:00
2025-05-01 11:11:48 +02:00
* * П о г а н о : * *
2019-01-31 10:18:41 +02:00
` ` ` ts
2019-02-06 09:57:52 +02:00
function parseCode ( code : string ) {
2019-01-31 10:18:41 +02:00
const REGEXES = [ /* ... */ ] ;
const statements = code . split ( ' ' ) ;
const tokens = [ ] ;
REGEXES . forEach ( ( regex ) = > {
statements . forEach ( ( statement ) = > {
// ...
} ) ;
} ) ;
const ast = [ ] ;
tokens . forEach ( ( token ) = > {
2025-05-01 11:11:48 +02:00
// лексичний аналіз...
2019-01-31 10:18:41 +02:00
} ) ;
ast . forEach ( ( node ) = > {
2025-05-01 11:11:48 +02:00
// парсинг...
2019-01-31 10:18:41 +02:00
} ) ;
}
` ` `
2025-05-01 11:11:48 +02:00
* * Д о б р е : * *
2019-01-31 10:18:41 +02:00
` ` ` ts
const REGEXES = [ /* ... */ ] ;
2019-02-06 09:57:52 +02:00
function parseCode ( code : string ) {
2019-01-31 10:18:41 +02:00
const tokens = tokenize ( code ) ;
const syntaxTree = parse ( tokens ) ;
syntaxTree . forEach ( ( node ) = > {
2025-05-01 11:11:48 +02:00
// парсинг...
2019-01-31 10:18:41 +02:00
} ) ;
}
2019-02-06 09:57:52 +02:00
function tokenize ( code : string ) : Token [ ] {
2019-01-31 10:18:41 +02:00
const statements = code . split ( ' ' ) ;
2019-02-06 09:57:52 +02:00
const tokens : Token [ ] = [ ] ;
2019-01-31 10:18:41 +02:00
REGEXES . forEach ( ( regex ) = > {
statements . forEach ( ( statement ) = > {
tokens . push ( /* ... */ ) ;
} ) ;
} ) ;
return tokens ;
}
function parse ( tokens : Token [ ] ) : SyntaxTree {
2019-02-06 09:57:52 +02:00
const syntaxTree : SyntaxTree [ ] = [ ] ;
2019-01-31 10:18:41 +02:00
tokens . forEach ( ( token ) = > {
syntaxTree . push ( /* ... */ ) ;
} ) ;
return syntaxTree ;
}
` ` `
2025-05-01 11:13:28 +02:00
* * [ ⬆ п о в е р н у т и с я д о з м і с т у ] ( # з м і с т ) * *
2019-01-31 10:18:41 +02:00
2025-05-01 11:11:48 +02:00
# # # В и д а л і т ь д у б л ь о в а н и й к о д
2019-01-31 10:18:41 +02:00
2025-05-01 11:11:48 +02:00
З р о б і т ь в с е м о ж л и в е , щ о б у н и к н у т и д у б л ь о в а н о г о к о д у .
Д у б л ь о в а н и й к о д п о г а н и й , т о м у щ о ц е о з н а ч а є , щ о і с н у є б і л ь ш е о д н о г о м і с ц я д л я з м і н и ч о г о с ь , я к щ о в а м п о т р і б н о з м і н и т и я к у с ь л о г і к у .
2019-01-31 10:18:41 +02:00
2025-05-01 11:11:48 +02:00
У я в і т ь , я к щ о в и к е р у є т е р е с т о р а н о м і в е д е т е о б л і к в а ш о г о інвентарю : всіх в а ш и х п о м і д о р і в , ц и б у л і , ч а с н и к у , с п е ц і й т о щ о .
Я к щ о у в а с є к і л ь к а с п и с к і в , д е в и ц е з б е р і г а є т е , т о в с і в о н и п о в и н н і б у т и о н о в л е н і , к о л и в и п о д а є т е с т р а в у з п о м і д о р а м и .
Я к щ о у в а с л и ш е о д и н с п и с о к , є л и ш е о д н е м і с ц е д л я о н о в л е н н я !
2019-01-31 10:18:41 +02:00
2025-05-01 11:11:48 +02:00
Ч а с т о в и м а є т е д у б л ь о в а н и й к о д , т о м у щ о у в а с є д в і а б о б і л ь ш е д е щ о р і з н и х р е ч е й , я к і м а ю т ь б а г а т о с п і л ь н о г о , а л е ї х н і в і д м і н н о с т і з м у ш у ю т ь в а с м а т и д в і а б о б і л ь ш е о к р е м і ф у н к ц і ї , я к і р о б л я т ь б а г а т о о д н а к о в и х р е ч е й . В и д а л е н н я д у б л ь о в а н о г о к о д у о з н а ч а є с т в о р е н н я а б с т р а к ц і ї , я к а м о ж е о б р о б л я т и ц е й н а б і р р і з н и х р е ч е й л и ш е о д н і є ю ф у н к ц і є ю / м о д у л е м / к л а с о м .
2019-01-31 10:18:41 +02:00
2025-05-01 11:11:48 +02:00
П р а в и л ь н а а б с т р а к ц і я є к р и т и ч н о ю , с а м е т о м у в и п о в и н н і д о т р и м у в а т и с я п р и н ц и п і в [ SOLID ] ( # solid ) . П о г а н і а б с т р а к ц і ї м о ж у т ь б у т и г і р ш и м и з а д у б л ь о в а н и й к о д , т о м у б у д ь т е о б е р е ж н і ! А л е я к щ о в и м о ж е т е з р о б и т и х о р о ш у а б с т р а к ц і ю , з р о б і т ь ц е ! Н е п о в т о р ю й т е с я , і н а к ш е в и б у д е т е о н о в л ю в а т и к і л ь к а м і с ц ь щ о р а з у , к о л и з а х о ч е т е з м і н и т и о д н у р і ч .
2019-01-31 10:18:41 +02:00
2025-05-01 11:11:48 +02:00
* * П о г а н о : * *
2019-01-31 10:18:41 +02:00
` ` ` ts
function showDeveloperList ( developers : Developer [ ] ) {
developers . forEach ( ( developer ) = > {
const expectedSalary = developer . calculateExpectedSalary ( ) ;
const experience = developer . getExperience ( ) ;
const githubLink = developer . getGithubLink ( ) ;
const data = {
expectedSalary ,
experience ,
githubLink
} ;
render ( data ) ;
} ) ;
}
function showManagerList ( managers : Manager [ ] ) {
managers . forEach ( ( manager ) = > {
const expectedSalary = manager . calculateExpectedSalary ( ) ;
const experience = manager . getExperience ( ) ;
const portfolio = manager . getMBAProjects ( ) ;
const data = {
expectedSalary ,
experience ,
portfolio
} ;
render ( data ) ;
} ) ;
}
` ` `
2025-05-01 11:11:48 +02:00
* * Д о б р е : * *
2019-01-31 10:18:41 +02:00
` ` ` ts
class Developer {
// ...
getExtraDetails() {
return {
githubLink : this.githubLink ,
}
}
}
class Manager {
// ...
getExtraDetails() {
return {
portfolio : this.portfolio ,
}
}
}
2022-07-15 13:58:56 +02:00
function showEmployeeList ( employee : ( Developer | Manager ) [ ] ) {
2019-01-31 10:18:41 +02:00
employee . forEach ( ( employee ) = > {
2019-02-06 12:25:36 +01:00
const expectedSalary = employee . calculateExpectedSalary ( ) ;
const experience = employee . getExperience ( ) ;
2019-01-31 10:18:41 +02:00
const extra = employee . getExtraDetails ( ) ;
const data = {
expectedSalary ,
experience ,
extra ,
} ;
render ( data ) ;
} ) ;
}
` ` `
2025-05-01 11:11:48 +02:00
В и т а к о ж м о ж е т е р о з г л я н у т и д о д а в а н н я т и п у о б ' є д н а н н я а б о с п і л ь н о г о б а т ь к і в с ь к о г о к л а с у , я к щ о ц е в і д п о в і д а є в а ш і й а б с т р а к ц і ї .
2022-07-15 13:58:56 +02:00
` ` ` ts
class Developer {
// ...
}
class Manager {
// ...
}
type Employee = Developer | Manager
function showEmployeeList ( employee : Employee [ ] ) {
// ...
} ) ;
}
` ` `
2025-05-01 11:11:48 +02:00
В и п о в и н н і к р и т и ч н о с т а в и т и с я д о д у б л ю в а н н я к о д у . І н о д і і с н у є к о м п р о м і с м і ж д у б л ь о в а н и м к о д о м і з б і л ь ш е н н я м с к л а д н о с т і ч е р е з в в е д е н н я н е п о т р і б н о ї а б с т р а к ц і ї . К о л и д в і р е а л і з а ц і ї з д в о х р і з н и х м о д у л і в в и г л я д а ю т ь с х о ж и м и , а л е ж и в у т ь у р і з н и х д о м е н а х , д у б л ю в а н н я м о ж е б у т и п р и й н я т н и м і п е р е в а ж а т и н а д в и т я г а н н я м с п і л ь н о г о к о д у . В и т я г н у т и й с п і л ь н и й к о д у ц ь о м у в и п а д к у с т в о р ю є н е п р я м у з а л е ж н і с т ь м і ж д в о м а м о д у л я м и .
2019-02-05 14:22:02 +02:00
2025-05-01 11:13:28 +02:00
* * [ ⬆ п о в е р н у т и с я д о з м і с т у ] ( # з м і с т ) * *
2019-01-31 10:18:41 +02:00
2025-05-01 11:11:48 +02:00
# # # В с т а н о в л ю й т е о б ' є к т и з а з а м о в ч у в а н н я м з а д о п о м о г о ю Object . assign а б о д е с т р у к т у р и з а ц і ї
2019-01-31 10:18:41 +02:00
2025-05-01 11:11:48 +02:00
* * П о г а н о : * *
2019-01-31 10:18:41 +02:00
` ` ` ts
2019-02-05 17:21:31 +02:00
type MenuConfig = { title? : string , body? : string , buttonText? : string , cancellable? : boolean } ;
2019-01-31 10:18:41 +02:00
function createMenu ( config : MenuConfig ) {
config . title = config . title || 'Foo' ;
config . body = config . body || 'Bar' ;
config . buttonText = config . buttonText || 'Baz' ;
config . cancellable = config . cancellable !== undefined ? config.cancellable : true ;
2019-02-06 09:57:52 +02:00
// ...
}
2019-01-31 10:18:41 +02:00
2019-02-06 09:57:52 +02:00
createMenu ( { body : 'Bar' } ) ;
2019-01-31 10:18:41 +02:00
` ` `
2025-05-01 11:11:48 +02:00
* * Д о б р е : * *
2019-01-31 10:18:41 +02:00
` ` ` ts
2019-02-05 17:21:31 +02:00
type MenuConfig = { title? : string , body? : string , buttonText? : string , cancellable? : boolean } ;
2019-01-31 10:18:41 +02:00
function createMenu ( config : MenuConfig ) {
const menuConfig = Object . assign ( {
title : 'Foo' ,
body : 'Bar' ,
buttonText : 'Baz' ,
cancellable : true
} , config ) ;
2019-02-06 09:57:52 +02:00
// ...
2019-01-31 10:18:41 +02:00
}
createMenu ( { body : 'Bar' } ) ;
` ` `
2025-05-01 11:11:48 +02:00
А б о в и м о ж е т е в и к о р и с т о в у в а т и о п е р а т о р п о ш и р е н н я ( spread operator ) :
2022-04-26 10:42:16 +03:00
` ` ` ts
function createMenu ( config : MenuConfig ) {
const menuConfig = {
title : 'Foo' ,
body : 'Bar' ,
buttonText : 'Baz' ,
cancellable : true ,
. . . config ,
} ;
// ...
}
` ` `
2025-05-01 11:11:48 +02:00
О п е р а т о р п о ш и р е н н я і ` Object.assign() ` д у ж е с х о ж і .
Г о л о в н а в і д м і н н і с т ь п о л я г а є в т о м у , щ о п о ш и р е н н я в и з н а ч а є н о в і в л а с т и в о с т і , т о д і я к ` Object.assign() ` в с т а н о в л ю є ї х . Б і л ь ш д е т а л ь н о ц я р і з н и ц я п о я с н ю є т ь с я в [ ц і й ] ( https : //stackoverflow.com/questions/32925460/object-spread-vs-object-assign) темі.
2022-04-26 10:42:16 +03:00
2025-05-01 11:11:48 +02:00
А л ь т е р н а т и в н о , в и м о ж е т е в и к о р и с т о в у в а т и д е с т р у к т у р и з а ц і ю з з н а ч е н н я м и з а з а м о в ч у в а н н я м :
2019-01-31 10:18:41 +02:00
` ` ` ts
2019-02-05 17:21:31 +02:00
type MenuConfig = { title? : string , body? : string , buttonText? : string , cancellable? : boolean } ;
2019-01-31 10:18:41 +02:00
2019-02-05 17:21:31 +02:00
function createMenu ( { title = 'Foo' , body = 'Bar' , buttonText = 'Baz' , cancellable = true } : MenuConfig ) {
2019-01-31 10:18:41 +02:00
// ...
}
createMenu ( { body : 'Bar' } ) ;
` ` `
2025-05-01 11:11:48 +02:00
Щ о б у н и к н у т и б у д ь - я к и х п о б і ч н и х е ф е к т і в і н е о ч і к у в а н о ї п о в е д і н к и п е р е д а ю ч и я в н о з н а ч е н н я ` undefined ` а б о ` null ` , в и м о ж е т е в к а з а т и к о м п і л я т о р у TypeScript н е д о з в о л я т и ц е .
Д и в і т ь с я о п ц і ю [ ` --strictNullChecks ` ] ( https : //www.typescriptlang.org/docs/handbook/release-notes/typescript-2-0.html#--strictnullchecks) в TypeScript.
2019-02-05 17:21:31 +02:00
2025-05-01 11:13:28 +02:00
* * [ ⬆ п о в е р н у т и с я д о з м і с т у ] ( # table - of - contents ) * *
2019-01-31 10:18:41 +02:00
2025-05-01 11:11:48 +02:00
# # # Н е в и к о р и с т о в у й т е п р а п о р ц і я к п а р а м е т р и ф у н к ц і й
2019-01-31 10:18:41 +02:00
2025-05-01 11:11:48 +02:00
П р а п о р ц і п о в і д о м л я ю т ь в а ш о м у к о р и с т у в а ч е в і , щ о ц я ф у н к ц і я р о б и т ь б і л ь ш е о д н і є ї р е ч і .
Ф у н к ц і ї п о в и н н і р о б и т и о д н у р і ч . Р о з д і л і т ь в а ш і ф у н к ц і ї , я к щ о в о н и с л і д у ю т ь р і з н и м ш л я х а м к о д у н а о с н о в і б у л е в о г о з н а ч е н н я .
2019-01-31 10:18:41 +02:00
2025-05-01 11:11:48 +02:00
* * П о г а н о : * *
2019-01-31 10:18:41 +02:00
` ` ` ts
2019-02-06 10:43:37 +02:00
function createFile ( name : string , temp : boolean ) {
2019-01-31 10:18:41 +02:00
if ( temp ) {
fs . create ( ` ./temp/ ${ name } ` ) ;
} else {
fs . create ( name ) ;
}
}
` ` `
2025-05-01 11:11:48 +02:00
* * Д о б р е : * *
2019-01-31 10:18:41 +02:00
` ` ` ts
2019-02-07 23:42:21 +02:00
function createTempFile ( name : string ) {
createFile ( ` ./temp/ ${ name } ` ) ;
2019-01-31 10:18:41 +02:00
}
2019-02-07 23:42:21 +02:00
function createFile ( name : string ) {
fs . create ( name ) ;
2019-01-31 10:18:41 +02:00
}
` ` `
2025-05-01 11:13:28 +02:00
* * [ ⬆ п о в е р н у т и с я д о з м і с т у ] ( # table - of - contents ) * *
2019-01-31 10:18:41 +02:00
2025-05-01 11:11:48 +02:00
# # # У н и к а й т е п о б і ч н и х е ф е к т і в ( ч а с т и н а 1 )
2019-01-31 10:18:41 +02:00
2025-05-01 11:11:48 +02:00
Ф у н к ц і я с т в о р ю є п о б і ч н и й е ф е к т , я к щ о в о н а р о б и т ь щ о с ь і н ш е , н і ж п р и й м а є з н а ч е н н я і п о в е р т а є і н ш е з н а ч е н н я а б о з н а ч е н н я .
П о б і ч н и м е ф е к т о м м о ж е б у т и з а п и с у ф а й л , з м і н а г л о б а л ь н о ї з м і н н о ї а б о в и п а д к о в е п е р е р а х у в а н н я в с і х в а ш и х г р о ш е й н е з н а й о м ц ю .
2019-01-31 10:18:41 +02:00
2025-05-01 11:11:48 +02:00
Ч а с в і д ч а с у в а м д і й с н о п о т р і б н і п о б і ч н і е ф е к т и в п р о г р а м і . Я к у п о п е р е д н ь о м у п р и к л а д і , в а м м о ж е з н а д о б и т и с я з а п и с у ф а й л .
А л е т е , щ о в и х о ч е т е з р о б и т и , ц е ц е н т р а л і з у в а т и м і с ц е , д е в и ц е р о б и т е . Н е м а й т е к і л ь к а ф у н к ц і й і к л а с і в , я к і з а п и с у ю т ь у п е в н и й ф а й л .
М а й т е о д н у с л у ж б у , я к а ц е р о б и т ь . О д н у і т і л ь к и о д н у .
2019-01-31 10:18:41 +02:00
2025-05-01 11:11:48 +02:00
О с н о в н а і д е я п о л я г а є в т о м у , щ о б у н и к н у т и п о ш и р е н и х п а с т о к , т а к и х я к о б м і н с т а н о м м і ж о б ' є к т а м и б е з с т р у к т у р и , в и к о р и с т а н н я м у т а б е л ь н и х т и п і в д а н и х , я к і м о ж у т ь б у т и з м і н е н і б у д ь - ч и м , і н е ц е н т р а л і з а ц і я т о г о , д е в і д б у в а ю т ь с я в а ш і п о б і ч н і е ф е к т и . Я к щ о в и з м о ж е т е ц е з р о б и т и , в и б у д е т е щ а с л и в і ш і , н і ж б і л ь ш і с т ь і н ш и х п р о г р а м і с т і в .
2019-01-31 10:18:41 +02:00
2025-05-01 11:11:48 +02:00
* * П о г а н о : * *
2019-01-31 10:18:41 +02:00
` ` ` ts
2025-05-01 11:11:48 +02:00
// Глобальна змінна, на яку посилається наступна функція.
2019-01-31 10:18:41 +02:00
let name = 'Robert C. Martin' ;
function toBase64() {
name = btoa ( name ) ;
}
2019-02-07 21:53:16 +02:00
toBase64 ( ) ;
2025-05-01 11:11:48 +02:00
// Якби у нас була інша функція, яка використовувала це ім'я, тепер це було б значення в Base64
2019-02-07 21:53:16 +02:00
2025-05-01 11:11:48 +02:00
console . log ( name ) ; // очікується, що надрукує 'Robert C. Martin', але натомість 'Um9iZXJ0IEMuIE1hcnRpbg=='
2019-01-31 10:18:41 +02:00
` ` `
2025-05-01 11:11:48 +02:00
* * Д о б р е : * *
2019-01-31 10:18:41 +02:00
` ` ` ts
const name = 'Robert C. Martin' ;
2019-02-06 09:57:52 +02:00
function toBase64 ( text : string ) : string {
2019-01-31 10:18:41 +02:00
return btoa ( text ) ;
}
2019-02-05 10:33:23 +01:00
const encodedName = toBase64 ( name ) ;
2019-01-31 10:18:41 +02:00
console . log ( name ) ;
` ` `
2025-05-01 11:13:28 +02:00
* * [ ⬆ п о в е р н у т и с я д о з м і с т у ] ( # table - of - contents ) * *
2019-01-31 10:18:41 +02:00
2025-05-01 11:11:48 +02:00
# # # У н и к а й т е п о б і ч н и х е ф е к т і в ( ч а с т и н а 2 )
2019-01-31 10:18:41 +02:00
2025-05-01 11:11:48 +02:00
Б р а у з е р и т а Node . js о б р о б л я ю т ь л и ш е JavaScript , т о м у б у д ь - я к и й к о д TypeScript м а є б у т и с к о м п і л ь о в а н и й п е р е д з а п у с к о м а б о н а л а г о д ж е н н я м . У JavaScript д е я к і з н а ч е н н я н е з м і н н і ( immutable ) , а д е я к і з м і н н і ( mutable ) . О б 'єкти та масиви є двома видами мутабельних значень, тому важливо обережно обробляти їх, коли вони передаються як параметри до функції. Функція JavaScript може змінювати властивості о б ' є к т а а б о з м і н ю в а т и в м і с т м а с и в у , щ о м о ж е л е г к о с п р и ч и н и т и п о м и л к и в і н ш и х м і с ц я х .
2019-01-31 10:18:41 +02:00
2025-05-01 11:11:48 +02:00
П р и п у с т и м о , і с н у є ф у н к ц і я , я к а п р и й м а є п а р а м е т р м а с и в у , щ о п р е д с т а в л я є к о ш и к п о к у п о к . Я к щ о ф у н к ц і я в н о с и т ь з м і н и в ц е й м а с и в к о ш и к а - н а п р и к л а д , д о д а ю ч и т о в а р д л я п о к у п к и - т о д і б у д ь - я к а і н ш а ф у н к ц і я , я к а в и к о р и с т о в у є т о й с а м и й м а с и в ` cart ` , б у д е п о р у ш е н а ц и м д о д а в а н н я м . Ц е м о ж е б у т и ч у д о в о , а л е т а к о ж м о ж е б у т и п о г а н о . Д а в а й т е у я в и м о п о г а н у с и т у а ц і ю :
2019-01-31 10:18:41 +02:00
2025-05-01 11:11:48 +02:00
К о р и с т у в а ч н а т и с к а є к н о п к у "Придбати" , я к а в и к л и к а є ф у н к ц і ю ` purchase ` , щ о с т в о р ю є м е р е ж е в и й з а п и т і н а д с и л а є м а с и в ` cart ` н а с е р в е р . Ч е р е з п о г а н е м е р е ж е в е з ' є д н а н н я ф у н к ц і я ` purchase ` п о в и н н а п о в т о р ю в а т и з а п и т . А щ о , я к щ о т и м ч а с о м к о р и с т у в а ч в и п а д к о в о н а т и с н е к н о п к у "Додати до кошика" н а т о в а р і , я к и й н а с п р а в д і н е х о ч е , п е р ш н і ж р о з п о ч н е т ь с я м е р е ж е в и й з а п и т ? Я к щ о ц е с т а н е т ь с я і м е р е ж е в и й з а п и т р о з п о ч н е т ь с я , ф у н к ц і я п о к у п к и н а д і ш л е в и п а д к о в о д о д а н и й т о в а р , о с к і л ь к и м а с и в ` cart ` б у в з м і н е н и й .
2022-04-26 09:58:56 +03:00
2025-05-01 11:11:48 +02:00
В і д м і н н и м р і ш е н н я м б у л о б д л я ф у н к ц і ї ` addItemToCart ` з а в ж д и к л о н у в а т и ` cart ` , р е д а г у в а т и й о г о і п о в е р т а т и к л о н . Ц е з а б е з п е ч и л о б , щ о ф у н к ц і ї , я к і в с е щ е в и к о р и с т о в у ю т ь с т а р и й к о ш и к п о к у п о к , н е б у д у т ь п о р у ш е н і з м і н а м и .
2019-01-31 10:18:41 +02:00
2025-05-01 11:11:48 +02:00
Д в а з а с т е р е ж е н н я щ о д о ц ь о г о п і д х о д у :
2019-01-31 10:18:41 +02:00
2025-05-01 11:11:48 +02:00
1 . М о ж у т ь б у т и в и п а д к и , к о л и в и д і й с н о х о ч е т е з м і н и т и в х і д н и й о б ' є к т , а л е к о л и в и п р и й м а є т е ц ю п р а к т и к у п р о г р а м у в а н н я , в и в и я в и т е , щ о т а к і в и п а д к и д о с и т ь р і д к і с н і . Б і л ь ш і с т ь р е ч е й м о ж н а п е р е р о б и т и т а к , щ о б н е б у л о п о б і ч н и х е ф е к т і в ! ( д и в . [ ч и с т а ф у н к ц і я ] ( https : //en.wikipedia.org/wiki/Pure_function))
2019-01-31 10:18:41 +02:00
2025-05-01 11:11:48 +02:00
2 . К л о н у в а н н я в е л и к и х о б 'єктів може бути дуже дорогим з точки зору продуктивності. Н а щастя, це не є великою проблемою на практиці, оскільки існують [чудові бібліотеки](https://github.com/immutable-js/immutable-js), які дозволяють такий підхід до програмування бути швидким і не таким інтенсивним щодо пам' я т і , я к ц е б у л о б д л я в а с в р у ч н у к л о н у в а т и о б ' є к т и т а м а с и в и .
2019-01-31 10:18:41 +02:00
2025-05-01 11:11:48 +02:00
* * П о г а н о : * *
2019-01-31 10:18:41 +02:00
` ` ` ts
2019-02-06 09:57:52 +02:00
function addItemToCart ( cart : CartItem [ ] , item : Item ) : void {
2019-01-31 10:18:41 +02:00
cart . push ( { item , date : Date.now ( ) } ) ;
} ;
` ` `
2025-05-01 11:11:48 +02:00
* * Д о б р е : * *
2019-01-31 10:18:41 +02:00
` ` ` ts
2019-02-06 09:57:52 +02:00
function addItemToCart ( cart : CartItem [ ] , item : Item ) : CartItem [ ] {
2019-02-05 12:56:25 +00:00
return [ . . . cart , { item , date : Date.now ( ) } ] ;
2019-01-31 10:18:41 +02:00
} ;
` ` `
2025-05-01 11:13:28 +02:00
* * [ ⬆ п о в е р н у т и с я д о з м і с т у ] ( # table - of - contents ) * *
2019-01-31 10:18:41 +02:00
2025-05-01 11:11:48 +02:00
# # # Н е п и ш і т ь д о г л о б а л ь н и х ф у н к ц і й
2019-01-31 10:18:41 +02:00
2025-05-01 11:11:48 +02:00
З а б р у д н е н н я г л о б а л ь н и х з м і н н и х є п о г а н о ю п р а к т и к о ю в JavaScript , о с к і л ь к и в и м о ж е т е з і т к н у т и с я з і н ш о ю б і б л і о т е к о ю , і к о р и с т у в а ч в а ш о г о API н е б у д е п р о ц е з н а т и , п о к и н е о т р и м а є в и н я т о к у п р о д а к ш е н і . Д а в а й т е п о д у м а є м о п р о приклад : що , я к щ о в и х о ч е т е р о з ш и р и т и н а т и в н и й м е т о д м а с и в у JavaScript , щ о б м а т и м е т о д ` diff ` , я к и й м і г б и п о к а з а т и р і з н и ц ю м і ж д в о м а м а с и в а м и ? В и м о г л и б н а п и с а т и с в о ю н о в у ф у н к ц і ю д о ` Array.prototype ` , а л е в о н а м о г л а б з і т к н у т и с я з і н ш о ю б і б л і о т е к о ю , я к а н а м а г а л а с я з р о б и т и т е с а м е . Щ о , я к щ о ц я і н ш а б і б л і о т е к а в и к о р и с т о в у в а л а ` diff ` л и ш е д л я п о ш у к у р і з н и ц і м і ж п е р ш и м і о с т а н н і м е л е м е н т а м и м а с и в у ? О с ь ч о м у б у л о б н а б а г а т о к р а щ е п р о с т о в и к о р и с т о в у в а т и к л а с и і п р о с т о р о з ш и р ю в а т и г л о б а л ь н и й ` Array ` .
2019-01-31 10:18:41 +02:00
2025-05-01 11:11:48 +02:00
* * П о г а н о : * *
2019-01-31 10:18:41 +02:00
` ` ` ts
declare global {
interface Array < T > {
diff ( other : T [ ] ) : Array < T > ;
}
}
2019-02-06 10:43:37 +02:00
if ( ! Array . prototype . diff ) {
2019-01-31 10:18:41 +02:00
Array . prototype . diff = function < T > ( other : T [ ] ) : T [ ] {
const hash = new Set ( other ) ;
return this . filter ( elem = > ! hash . has ( elem ) ) ;
} ;
}
` ` `
2025-05-01 11:11:48 +02:00
* * Д о б р е : * *
2019-01-31 10:18:41 +02:00
` ` ` ts
class MyArray < T > extends Array < T > {
diff ( other : T [ ] ) : T [ ] {
const hash = new Set ( other ) ;
return this . filter ( elem = > ! hash . has ( elem ) ) ;
} ;
}
` ` `
2025-05-01 11:13:28 +02:00
* * [ ⬆ п о в е р н у т и с я д о з м і с т у ] ( # table - of - contents ) * *
2019-01-31 10:18:41 +02:00
2025-05-01 11:11:48 +02:00
# # # В і д д а в а й т е п е р е в а г у ф у н к ц і о н а л ь н о м у п р о г р а м у в а н н ю н а д і м п е р а т и в н и м
2019-01-31 10:18:41 +02:00
2025-05-01 11:11:48 +02:00
В і д д а в а й т е п е р е в а г у ц ь о м у с т и л ю п р о г р а м у в а н н я , к о л и м о ж е т е .
2019-01-31 10:18:41 +02:00
2025-05-01 11:11:48 +02:00
* * П о г а н о : * *
2019-01-31 10:18:41 +02:00
` ` ` ts
const contributions = [
{
name : 'Uncle Bobby' ,
linesOfCode : 500
} , {
name : 'Suzie Q' ,
linesOfCode : 1500
} , {
name : 'Jimmy Gosling' ,
linesOfCode : 150
} , {
name : 'Gracie Hopper' ,
linesOfCode : 1000
}
] ;
let totalOutput = 0 ;
for ( let i = 0 ; i < contributions . length ; i ++ ) {
totalOutput += contributions [ i ] . linesOfCode ;
}
` ` `
2025-05-01 11:11:48 +02:00
* * Д о б р е : * *
2019-01-31 10:18:41 +02:00
` ` ` ts
const contributions = [
{
name : 'Uncle Bobby' ,
linesOfCode : 500
} , {
name : 'Suzie Q' ,
linesOfCode : 1500
} , {
name : 'Jimmy Gosling' ,
linesOfCode : 150
} , {
name : 'Gracie Hopper' ,
linesOfCode : 1000
}
] ;
const totalOutput = contributions
2019-02-06 10:48:34 +02:00
. reduce ( ( totalLines , output ) = > totalLines + output . linesOfCode , 0 ) ;
2019-01-31 10:18:41 +02:00
` ` `
2025-05-01 11:13:28 +02:00
* * [ ⬆ п о в е р н у т и с я д о з м і с т у ] ( # table - of - contents ) * *
2019-01-31 10:18:41 +02:00
2025-05-01 11:11:48 +02:00
# # # І н к а п с у л ю й т е у м о в и
2019-01-31 10:18:41 +02:00
2025-05-01 11:11:48 +02:00
* * П о г а н о : * *
2019-01-31 10:18:41 +02:00
` ` ` ts
if ( subscription . isTrial || account . balance > 0 ) {
// ...
}
` ` `
2025-05-01 11:11:48 +02:00
* * Д о б р е : * *
2019-01-31 10:18:41 +02:00
` ` ` ts
function canActivateService ( subscription : Subscription , account : Account ) {
2020-04-09 15:56:59 +09:00
return subscription . isTrial || account . balance > 0 ;
2019-01-31 10:18:41 +02:00
}
if ( canActivateService ( subscription , account ) ) {
// ...
}
` ` `
2025-05-01 11:13:28 +02:00
* * [ ⬆ п о в е р н у т и с я д о з м і с т у ] ( # table - of - contents ) * *
2019-01-31 10:18:41 +02:00
2025-05-01 11:11:48 +02:00
# # # У н и к а й т е н е г а т и в н и х у м о в
2019-01-31 10:18:41 +02:00
2025-05-01 11:11:48 +02:00
* * П о г а н о : * *
2019-01-31 10:18:41 +02:00
` ` ` ts
2019-02-06 09:57:52 +02:00
function isEmailNotUsed ( email : string ) : boolean {
2019-01-31 10:18:41 +02:00
// ...
}
if ( isEmailNotUsed ( email ) ) {
// ...
}
` ` `
2025-05-01 11:11:48 +02:00
* * Д о б р е : * *
2019-01-31 10:18:41 +02:00
` ` ` ts
2020-05-25 09:47:24 +03:00
function isEmailUsed ( email : string ) : boolean {
2019-01-31 10:18:41 +02:00
// ...
}
2021-11-12 14:41:22 -08:00
if ( ! isEmailUsed ( email ) ) {
2019-01-31 10:18:41 +02:00
// ...
}
` ` `
2025-05-01 11:13:28 +02:00
* * [ ⬆ п о в е р н у т и с я д о з м і с т у ] ( # table - of - contents ) * *
2019-01-31 10:18:41 +02:00
2025-05-01 11:11:48 +02:00
# # # У н и к а й т е у м о в
2019-01-31 10:18:41 +02:00
2025-05-01 11:11:48 +02:00
Ц е з д а є т ь с я н е м о ж л и в и м з а в д а н н я м . П р и п е р ш о м у п о ч у т т і ц ь о г о б і л ь ш і с т ь л ю д е й к а ж е : "Як я повинен щось робити без оператора `if`?" В і д п о в і д ь п о л я г а є в т о м у , щ о в и м о ж е т е в и к о р и с т о в у в а т и п о л і м о р ф і з м д л я д о с я г н е н н я т і є ї ж з а д а ч і в б а г а т ь о х в и п а д к а х . Д р у г е п и т а н н я з а з в и ч а й : "Н у , це чудово, але чому я повинен це робити?" В і д п о в і д ь - ц е п о п е р е д н я к о н ц е п ц і я ч и с т о г о к о д у , я к у м и вивчили : функція п о в и н н а р о б и т и т і л ь к и о д н у р і ч . К о л и у в а с є к л а с и т а ф у н к ц і ї , я к і м а ю т ь о п е р а т о р и ` if ` , в и п о в і д о м л я є т е с в о є м у к о р и с т у в а ч е в і , щ о в а ш а ф у н к ц і я р о б и т ь б і л ь ш е о д н і є ї р е ч і . П а м ' я т а й т е , р о б і т ь л и ш е о д н у р і ч .
2019-01-31 10:18:41 +02:00
2025-05-01 11:11:48 +02:00
* * П о г а н о : * *
2019-01-31 10:18:41 +02:00
` ` ` ts
class Airplane {
private type : string ;
// ...
2019-02-07 21:53:16 +02:00
2019-01-31 10:18:41 +02:00
getCruisingAltitude() {
switch ( this . type ) {
case '777' :
return this . getMaxAltitude ( ) - this . getPassengerCount ( ) ;
case 'Air Force One' :
return this . getMaxAltitude ( ) ;
case 'Cessna' :
return this . getMaxAltitude ( ) - this . getFuelExpenditure ( ) ;
default :
throw new Error ( 'Unknown airplane type.' ) ;
}
}
2019-02-06 09:57:52 +02:00
2019-02-06 10:43:37 +02:00
private getMaxAltitude ( ) : number {
2019-02-06 09:57:52 +02:00
// ...
}
2019-01-31 10:18:41 +02:00
}
` ` `
2025-05-01 11:11:48 +02:00
* * Д о б р е : * *
2019-01-31 10:18:41 +02:00
` ` ` ts
2019-02-06 09:57:52 +02:00
abstract class Airplane {
2019-02-06 10:43:37 +02:00
protected getMaxAltitude ( ) : number {
2025-05-01 11:11:48 +02:00
// спільна логіка з підкласами ...
2019-02-06 09:57:52 +02:00
}
2019-01-31 10:18:41 +02:00
// ...
}
class Boeing777 extends Airplane {
// ...
getCruisingAltitude() {
return this . getMaxAltitude ( ) - this . getPassengerCount ( ) ;
}
}
class AirForceOne extends Airplane {
// ...
getCruisingAltitude() {
return this . getMaxAltitude ( ) ;
}
}
class Cessna extends Airplane {
// ...
getCruisingAltitude() {
return this . getMaxAltitude ( ) - this . getFuelExpenditure ( ) ;
}
}
` ` `
2025-05-01 11:13:28 +02:00
* * [ ⬆ п о в е р н у т и с я д о з м і с т у ] ( # table - of - contents ) * *
2019-01-31 10:18:41 +02:00
2025-05-01 11:11:48 +02:00
# # # У н и к а й т е п е р е в і р к и т и п і в
2019-01-31 10:18:41 +02:00
2025-05-01 11:11:48 +02:00
TypeScript є с т р о г и м с и н т а к с и ч н и м р о з ш и р е н н я м JavaScript і д о д а є н е о б о в ' я з к о в у с т а т и ч н у п е р е в і р к у т и п і в д о м о в и .
З а в ж д и в і д д а в а й т е п е р е в а г у в к а з а н н ю т и п і в з м і н н и х , п а р а м е т р і в і з н а ч е н ь , щ о п о в е р т а ю т ь с я , щ о б в и к о р и с т о в у в а т и п о в н у с и л у м о ж л и в о с т е й TypeScript .
Ц е р о б и т ь р е ф а к т о р и н г л е г ш и м .
2019-01-31 10:18:41 +02:00
2025-05-01 11:11:48 +02:00
* * П о г а н о : * *
2019-01-31 10:18:41 +02:00
` ` ` ts
function travelToTexas ( vehicle : Bicycle | Car ) {
if ( vehicle instanceof Bicycle ) {
2019-02-06 09:57:52 +02:00
vehicle . pedal ( currentLocation , new Location ( 'texas' ) ) ;
2019-01-31 10:18:41 +02:00
} else if ( vehicle instanceof Car ) {
2019-02-06 09:57:52 +02:00
vehicle . drive ( currentLocation , new Location ( 'texas' ) ) ;
2019-01-31 10:18:41 +02:00
}
}
` ` `
2025-05-01 11:11:48 +02:00
* * Д о б р е : * *
2019-01-31 10:18:41 +02:00
` ` ` ts
type Vehicle = Bicycle | Car ;
function travelToTexas ( vehicle : Vehicle ) {
2019-02-06 09:57:52 +02:00
vehicle . move ( currentLocation , new Location ( 'texas' ) ) ;
2019-01-31 10:18:41 +02:00
}
` ` `
2025-05-01 11:13:28 +02:00
* * [ ⬆ п о в е р н у т и с я д о з м і с т у ] ( # table - of - contents ) * *
2019-01-31 10:18:41 +02:00
2025-05-01 11:11:48 +02:00
# # # Н е о п т и м і з у й т е н а д м і р н о
2019-01-31 10:18:41 +02:00
2025-05-01 11:11:48 +02:00
С у ч а с н і б р а у з е р и в и к о н у ю т ь б а г а т о о п т и м і з а ц і й п і д к а п о т о м п і д ч а с в и к о н а н н я . Ч а с т о , я к щ о в и о п т и м і з у є т е , в и п р о с т о в и т р а ч а є т е с в і й ч а с . Є х о р о ш і [ р е с у р с и ] ( https : //github.com/petkaantonov/bluebird/wiki/Optimization-killers) для перегляду, де оптимізація не вистачає. Націльтеся на них, поки вони не будуть виправлені, якщо це можливо.
2019-01-31 10:18:41 +02:00
2025-05-01 11:11:48 +02:00
* * П о г а н о : * *
2019-01-31 10:18:41 +02:00
` ` ` ts
2025-05-01 11:11:48 +02:00
// Н а старих браузерах кожна ітерація з незакешованою `list.length` була б дорогою
// через перераховування `list.length`. У сучасних браузерах це оптимізовано.
2019-01-31 10:18:41 +02:00
for ( let i = 0 , len = list . length ; i < len ; i ++ ) {
// ...
}
` ` `
2025-05-01 11:11:48 +02:00
* * Д о б р е : * *
2019-01-31 10:18:41 +02:00
` ` ` ts
for ( let i = 0 ; i < list . length ; i ++ ) {
// ...
}
` ` `
2025-05-01 11:13:28 +02:00
* * [ ⬆ п о в е р н у т и с я д о з м і с т у ] ( # table - of - contents ) * *
2019-01-31 10:18:41 +02:00
2025-05-01 11:11:48 +02:00
# # # В и д а л я й т е м е р т в и й к о д
2019-01-31 10:18:41 +02:00
2025-05-01 11:11:48 +02:00
М е р т в и й к о д т а к с а м о п о г а н и й , я к і д у б л ю в а н н я к о д у . Н е м а є п р и ч и н т р и м а т и й о г о у в а ш і й к о д о в і й б а з і .
Я к щ о в і н н е в и к л и к а є т ь с я , п о з б у д ь т е с я й о г о ! В і н в с е щ е б у д е з б е р е ж е н и й у в а ш і й і с т о р і ї в е р с і й , я к щ о в а м в і н щ е з н а д о б и т ь с я .
2019-01-31 10:18:41 +02:00
2025-05-01 11:11:48 +02:00
* * П о г а н о : * *
2019-01-31 10:18:41 +02:00
` ` ` ts
function oldRequestModule ( url : string ) {
// ...
}
function requestModule ( url : string ) {
// ...
}
const req = requestModule ;
inventoryTracker ( 'apples' , req , 'www.inventory-awesome.io' ) ;
` ` `
2025-05-01 11:11:48 +02:00
* * Д о б р е : * *
2019-01-31 10:18:41 +02:00
` ` ` ts
2019-02-05 08:51:37 +02:00
function requestModule ( url : string ) {
2019-01-31 10:18:41 +02:00
// ...
}
2019-02-05 08:51:37 +02:00
const req = requestModule ;
inventoryTracker ( 'apples' , req , 'www.inventory-awesome.io' ) ;
2019-01-31 10:18:41 +02:00
` ` `
2025-05-01 11:13:28 +02:00
* * [ ⬆ п о в е р н у т и с я д о з м і с т у ] ( # table - of - contents ) * *
2019-01-31 10:18:41 +02:00
2025-05-01 11:11:48 +02:00
# # # В и к о р и с т о в у й т е і т е р а т о р и т а г е н е р а т о р и
2019-02-09 23:28:17 +02:00
2025-05-01 11:11:48 +02:00
В и к о р и с т о в у й т е г е н е р а т о р и т а і т е р а б е л ь н і о б ' є к т и п р и р о б о т і з к о л е к ц і я м и д а н и х , щ о в и к о р и с т о в у ю т ь с я я к п о т і к .
Н а ц е є к і л ь к а п р и ч и н :
2019-02-12 08:40:50 +02:00
2025-05-01 11:11:48 +02:00
- в і д о к р е м л ю є в и к л и к в і д р е а л і з а ц і ї г е н е р а т о р а в т о м у с е н с і , щ о в и к л и к в и р і ш у є , с к і л ь к и е л е м е н т і в д о с т у п у
- л і н и в а і н і ц і а л і з а ц і я , е л е м е н т и т р а н с л ю ю т ь с я з а з а п и т о м
- в б у д о в а н а п і д т р и м к а д л я і т е р а ц і ї е л е м е н т і в з а д о п о м о г о ю с и н т а к с и с у ` for-of `
- і т е р а б е л ь н і о б ' є к т и д о з в о л я ю т ь р е а л і з о в у в а т и о п т и м і з о в а н і ш а б л о н и і т е р а т о р а
2019-02-09 23:28:17 +02:00
2025-05-01 11:11:48 +02:00
* * П о г а н о : * *
2019-02-09 23:28:17 +02:00
` ` ` ts
function fibonacci ( n : number ) : number [ ] {
if ( n === 1 ) return [ 0 ] ;
if ( n === 2 ) return [ 0 , 1 ] ;
2019-02-12 08:40:50 +02:00
const items : number [ ] = [ 0 , 1 ] ;
2019-02-09 23:28:17 +02:00
while ( items . length < n ) {
items . push ( items [ items . length - 2 ] + items [ items . length - 1 ] ) ;
}
return items ;
}
function print ( n : number ) {
fibonacci ( n ) . forEach ( fib = > console . log ( fib ) ) ;
}
2025-05-01 11:11:48 +02:00
// Виведення перших 10 чисел Фібоначчі.
2019-02-09 23:28:17 +02:00
print ( 10 ) ;
` ` `
2025-05-01 11:11:48 +02:00
* * Д о б р е : * *
2019-02-09 23:28:17 +02:00
` ` ` ts
2025-05-01 11:11:48 +02:00
// Генерує нескінченний потік чисел Фібоначчі.
// Генератор не зберігає масив у с і х чисел.
2019-02-09 23:28:17 +02:00
function * fibonacci ( ) : IterableIterator < number > {
let [ a , b ] = [ 0 , 1 ] ;
2019-02-12 08:40:50 +02:00
2019-02-09 23:28:17 +02:00
while ( true ) {
yield a ;
[ a , b ] = [ b , a + b ] ;
}
}
function print ( n : number ) {
let i = 0 ;
2019-02-27 19:46:04 +05:45
for ( const fib of fibonacci ( ) ) {
2019-02-09 23:28:17 +02:00
if ( i ++ === n ) break ;
console . log ( fib ) ;
}
}
2025-05-01 11:11:48 +02:00
// Виведення перших 10 чисел Фібоначчі.
2019-02-09 23:28:17 +02:00
print ( 10 ) ;
` ` `
2025-05-01 11:11:48 +02:00
І с н у ю т ь б і б л і о т е к и , я к і д о з в о л я ю т ь п р а ц ю в а т и з і т е р а б е л ь н и м и о б ' є к т а м и а н а л о г і ч н о н а т и в н и м м а с и в а м , ш л я х о м
л а н ц ю ж к а м е т о д і в , т а к и х я к ` map ` , ` slice ` , ` forEach ` т о щ о . Д и в і т ь с я [ itiriri ] ( https : //www.npmjs.com/package/itiriri) для
п р и к л а д у р о з ш и р е н о г о м а н і п у л ю в а н н я з і т е р а б е л ь н и м и о б 'єктами (а б о [itiriri-async](https://www.npmjs.com/package/itiriri-async) для маніпуляцій з асинхронними ітерабельними о б ' є к т а м и ) .
2019-02-09 23:28:17 +02:00
` ` ` ts
import itiriri from 'itiriri' ;
function * fibonacci ( ) : IterableIterator < number > {
let [ a , b ] = [ 0 , 1 ] ;
while ( true ) {
yield a ;
[ a , b ] = [ b , a + b ] ;
}
}
itiriri ( fibonacci ( ) )
. take ( 10 )
. forEach ( fib = > console . log ( fib ) ) ;
` ` `
2025-05-01 11:13:28 +02:00
* * [ ⬆ п о в е р н у т и с я д о з м і с т у ] ( # table - of - contents ) * *
2019-02-09 23:28:17 +02:00
2025-05-01 11:11:48 +02:00
# # О б ' є к т и т а с т р у к т у р и д а н и х
2019-01-29 09:44:59 +02:00
2025-05-01 11:11:48 +02:00
# # # В и к о р и с т о в у й т е г е т т е р и т а с е т т е р и
2019-01-29 09:44:59 +02:00
2025-05-01 11:11:48 +02:00
TypeScript п і д т р и м у є с и н т а к с и с г е т т е р а / с е т т е р а .
В и к о р и с т а н н я г е т т е р і в і с е т т е р і в д л я д о с т у п у д о д а н и х з о б 'єктів, які інкапсулюють поведінку, може бути кращим, ніж просто пошук властивості о б ' є к т а .
"Чому?" в и м о ж е т е з а п и т а т и . О с ь с п и с о к п р и ч и н :
2019-01-29 09:44:59 +02:00
2025-05-01 11:11:48 +02:00
- К о л и в и х о ч е т е з р о б и т и б і л ь ш е , н і ж о т р и м а т и в л а с т и в і с т ь о б ' є к т а , в а м н е п о т р і б н о ш у к а т и т а з м і н ю в а т и к о ж е н д о с т у п у в а ш і й к о д о в і й б а з і .
- Р о б и т ь д о д а в а н н я в а л і д а ц і ї п р о с т и м п р и в и к о р и с т а н н і ` set ` .
- І н к а п с у л ю є в н у т р і ш н є п р е д с т а в л е н н я .
- Л е г к о д о д а т и л о г у в а н н я т а о б р о б к у п о м и л о к п р и о т р и м а н н і т а в с т а н о в л е н н і .
- В и м о ж е т е л і н и в а з а в а н т а ж у в а т и в л а с т и в о с т і в а ш о г о о б ' є к т а , н а п р и к л а д , о т р и м у ю ч и ї х з с е р в е р а .
2019-01-29 09:44:59 +02:00
2025-05-01 11:11:48 +02:00
* * П о г а н о : * *
2019-01-29 09:44:59 +02:00
` ` ` ts
2019-02-07 21:53:16 +02:00
type BankAccount = {
balance : number ;
2019-01-29 09:44:59 +02:00
// ...
}
const value = 100 ;
2019-02-12 08:40:50 +02:00
const account : BankAccount = {
2019-02-07 21:53:16 +02:00
balance : 0 ,
2019-02-12 08:40:50 +02:00
// ...
2019-02-07 21:53:16 +02:00
} ;
2019-01-29 09:44:59 +02:00
if ( value < 0 ) {
throw new Error ( 'Cannot set negative balance.' ) ;
}
account . balance = value ;
` ` `
2025-05-01 11:11:48 +02:00
* * Д о б р е : * *
2019-01-29 09:44:59 +02:00
` ` ` ts
class BankAccount {
private accountBalance : number = 0 ;
get balance ( ) : number {
return this . accountBalance ;
}
set balance ( value : number ) {
if ( value < 0 ) {
throw new Error ( 'Cannot set negative balance.' ) ;
}
this . accountBalance = value ;
}
// ...
}
2025-05-01 11:11:48 +02:00
// Тепер `BankAccount` інкапсулює логіку валідації.
// Якщо одного дня специфікації зміняться, і нам знадобиться додаткове правило валідації,
// нам потрібно буде змінити лише реалізацію `setter`,
// залишаючи весь залежний код незмішним.
2019-01-29 09:44:59 +02:00
const account = new BankAccount ( ) ;
account . balance = 100 ;
` ` `
2025-05-01 11:13:28 +02:00
* * [ ⬆ п о в е р н у т и с я д о з м і с т у ] ( # table - of - contents ) * *
2019-01-29 09:44:59 +02:00
2025-05-01 11:11:48 +02:00
# # # С т в о р ю й т е о б ' є к т и з п р и в а т н и м и / з а х и щ е н и м и ч л е н а м и
2019-01-29 09:44:59 +02:00
2025-05-01 11:11:48 +02:00
TypeScript п і д т р и м у є ` public ` * ( з а з а м о в ч у в а н н я м ) * , ` protected ` т а ` private ` м о д и ф і к а т о р и д о с т у п у д л я ч л е н і в к л а с у .
2019-01-29 09:44:59 +02:00
2025-05-01 11:11:48 +02:00
* * П о г а н о : * *
2019-01-29 09:44:59 +02:00
` ` ` ts
class Circle {
radius : number ;
constructor ( radius : number ) {
this . radius = radius ;
}
2019-02-06 09:57:52 +02:00
perimeter() {
2019-01-29 09:44:59 +02:00
return 2 * Math . PI * this . radius ;
}
2019-02-06 09:57:52 +02:00
surface() {
2019-01-29 09:44:59 +02:00
return Math . PI * this . radius * this . radius ;
}
}
` ` `
2025-05-01 11:11:48 +02:00
* * Д о б р е : * *
2019-01-29 09:44:59 +02:00
` ` ` ts
class Circle {
constructor ( private readonly radius : number ) {
}
2019-02-06 09:57:52 +02:00
perimeter() {
2019-01-29 09:44:59 +02:00
return 2 * Math . PI * this . radius ;
}
2019-02-06 09:57:52 +02:00
surface() {
2019-01-29 09:44:59 +02:00
return Math . PI * this . radius * this . radius ;
}
}
` ` `
2025-05-01 11:13:28 +02:00
* * [ ⬆ п о в е р н у т и с я д о з м і с т у ] ( # table - of - contents ) * *
2019-01-29 09:44:59 +02:00
2025-05-01 11:11:48 +02:00
# # # В і д д а в а й т е п е р е в а г у н е з м і н н о с т і
2019-01-29 09:44:59 +02:00
2025-05-01 11:11:48 +02:00
С и с т е м а т и п і в TypeScript д о з в о л я є п о з н а ч а т и о к р е м і в л а с т и в о с т і в і н т е р ф е й с і / к л а с і я к * readonly * . Ц е д о з в о л я є п р а ц ю в а т и у ф у н к ц і о н а л ь н о м у с т и л і ( н е с п о д і в а н а м у т а ц і я є п о г а н о ю п р а к т и к о ю ) .
Д л я б і л ь ш с к л а д н и х с ц е н а р і ї в і с н у є в б у д о в а н и й т и п ` Readonly ` , я к и й п р и й м а є т и п ` T ` і п о з н а ч а є в с і й о г о в л а с т и в о с т і я к readonly , в и к о р и с т о в у ю ч и в і д о б р а ж е н і т и п и ( д и в . [ в і д о б р а ж е н і т и п и ] ( https : //www.typescriptlang.org/docs/handbook/advanced-types.html#mapped-types)).
2019-01-29 09:44:59 +02:00
2025-05-01 11:11:48 +02:00
* * П о г а н о : * *
2019-01-29 09:44:59 +02:00
` ` ` ts
interface Config {
host : string ;
port : string ;
db : string ;
}
` ` `
2025-05-01 11:11:48 +02:00
* * Д о б р е : * *
2019-01-29 09:44:59 +02:00
` ` ` ts
interface Config {
readonly host : string ;
readonly port : string ;
readonly db : string ;
}
` ` `
2025-05-01 11:11:48 +02:00
Д л я м а с и в і в в и м о ж е т е с т в о р и т и м а с и в т і л ь к и д л я ч и т а н н я , в и к о р и с т о в у ю ч и ` ReadonlyArray<T> ` .
В і н н е д о з в о л я є з м і н и , т а к і я к ` push() ` т а ` fill() ` , а л е м о ж н а в и к о р и с т о в у в а т и ф у н к ц і ї , т а к і я к ` concat() ` т а ` slice() ` , я к і н е з м і н ю ю т ь з н а ч е н н я м а с и в у .
2019-05-30 20:26:06 +09:00
2025-05-01 11:11:48 +02:00
* * П о г а н о : * *
2019-05-30 20:26:06 +09:00
` ` ` ts
const array : number [ ] = [ 1 , 3 , 5 ] ;
2025-05-01 11:11:48 +02:00
array = [ ] ; // помилка
array . push ( 100 ) ; // масив буде оновлено
2019-05-30 20:26:06 +09:00
` ` `
2025-05-01 11:11:48 +02:00
* * Д о б р е : * *
2019-05-30 20:26:06 +09:00
` ` ` ts
const array : ReadonlyArray < number > = [ 1 , 3 , 5 ] ;
2025-05-01 11:11:48 +02:00
array = [ ] ; // помилка
array . push ( 100 ) ; // помилка
2019-05-30 20:26:06 +09:00
` ` `
2025-05-01 11:11:48 +02:00
О г о л о ш е н н я а р г у м е н т і в л и ш е д л я ч и т а н н я у [ TypeScript 3.4 є т р о х и п р о с т і ш и м ] ( https : //github.com/microsoft/TypeScript/wiki/What's-new-in-TypeScript#improvements-for-readonlyarray-and-readonly-tuples).
2019-05-30 20:26:06 +09:00
` ` ` ts
function hoge ( args : readonly string [ ] ) {
2025-05-01 11:11:48 +02:00
args . push ( 1 ) ; // помилка
2019-05-30 20:26:06 +09:00
}
` ` `
2025-05-01 11:11:48 +02:00
В і д д а в а й т е п е р е в а г у [ к о н с т а н т н и м т в е р д ж е н н я м ] ( https : //github.com/microsoft/TypeScript/wiki/What's-new-in-TypeScript#const-assertions) для літеральних значень.
2019-05-30 20:26:06 +09:00
2025-05-01 11:11:48 +02:00
* * П о г а н о : * *
2019-05-30 20:26:06 +09:00
` ` ` ts
const config = {
hello : 'world'
} ;
2025-05-01 11:11:48 +02:00
config . hello = 'world' ; // значення змінюється
2019-05-30 20:26:06 +09:00
const array = [ 1 , 3 , 5 ] ;
2025-05-01 11:11:48 +02:00
array [ 0 ] = 10 ; // значення змінюється
2019-05-30 20:26:06 +09:00
2025-05-01 11:11:48 +02:00
// повертаються о б 'єкти, які можна змінювати
2019-05-30 20:26:06 +09:00
function readonlyData ( value : number ) {
return { value } ;
}
const result = readonlyData ( 100 ) ;
2025-05-01 11:11:48 +02:00
result . value = 200 ; // значення змінюється
2019-05-30 20:26:06 +09:00
` ` `
2025-05-01 11:11:48 +02:00
* * Д о б р е : * *
2019-05-30 20:26:06 +09:00
` ` ` ts
2025-05-01 11:11:48 +02:00
// о б 'єкт тільки для читання
2019-05-30 20:26:06 +09:00
const config = {
hello : 'world'
} as const ;
2025-05-01 11:11:48 +02:00
config . hello = 'world' ; // помилка
2019-05-30 20:26:06 +09:00
2025-05-01 11:11:48 +02:00
// масив тільки для читання
2019-05-30 20:26:06 +09:00
const array = [ 1 , 3 , 5 ] as const ;
2025-05-01 11:11:48 +02:00
array [ 0 ] = 10 ; // помилка
2019-05-30 20:26:06 +09:00
2025-05-01 11:11:48 +02:00
// Ви можете повертати о б 'єкти тільки для читання
2019-05-30 20:26:06 +09:00
function readonlyData ( value : number ) {
return { value } as const ;
}
const result = readonlyData ( 100 ) ;
2025-05-01 11:11:48 +02:00
result . value = 200 ; // помилка
2019-05-30 20:26:06 +09:00
` ` `
2025-05-01 11:13:28 +02:00
* * [ ⬆ п о в е р н у т и с я д о з м і с т у ] ( # table - of - contents ) * *
2019-02-04 18:18:27 +02:00
2025-05-01 11:11:48 +02:00
# # # type п р о т и interface
2019-02-11 13:39:31 +02:00
2025-05-01 11:11:48 +02:00
В и к о р и с т о в у й т е type , к о л и в а м м о ж е з н а д о б и т и с я о б ' є д н а н н я а б о п е р е т и н . В и к о р и с т о в у й т е interface , к о л и в и х о ч е т е в и к о р и с т о в у в а т и ` extends ` а б о ` implements ` . Н е м а є с т р о г о г о п р а в и л а , п р о т е в и к о р и с т о в у й т е т е , щ о п р а ц ю є д л я в а с .
Д л я б і л ь ш д е т а л ь н о г о п о я с н е н н я з в е р н і т ь с я д о ц і є ї [ в і д п о в і д і ] ( https : //stackoverflow.com/questions/37233735/typescript-interfaces-vs-types/54101543#54101543) про відмінності між `type` і `interface` у TypeScript.
2019-02-11 13:39:31 +02:00
2025-05-01 11:11:48 +02:00
* * П о г а н о : * *
2019-02-11 13:39:31 +02:00
` ` ` ts
interface EmailConfig {
// ...
}
interface DbConfig {
// ...
}
interface Config {
// ...
}
//...
2019-02-13 19:15:40 +09:00
type Shape = {
2019-02-11 13:39:31 +02:00
// ...
}
` ` `
2025-05-01 11:11:48 +02:00
* * Д о б р е : * *
2019-02-11 13:39:31 +02:00
` ` ` ts
2019-02-13 19:15:40 +09:00
type EmailConfig = {
2019-02-11 13:39:31 +02:00
// ...
}
2019-02-13 19:15:40 +09:00
type DbConfig = {
2019-02-11 13:39:31 +02:00
// ...
}
type Config = EmailConfig | DbConfig ;
// ...
interface Shape {
// ...
}
class Circle implements Shape {
// ...
}
class Square implements Shape {
// ...
}
` ` `
2025-05-01 11:13:28 +02:00
* * [ ⬆ п о в е р н у т и с я д о з м і с т у ] ( # table - of - contents ) * *
2019-02-11 13:39:31 +02:00
2025-05-01 11:11:48 +02:00
# # К л а с и
2019-02-04 18:09:04 +02:00
2025-05-01 11:11:48 +02:00
# # # К л а с и п о в и н н і б у т и м а л и м и
2019-02-04 18:09:04 +02:00
2025-05-01 11:11:48 +02:00
Р о з м і р к л а с у в и м і р ю є т ь с я й о г о в і д п о в і д а л ь н і с т ю . С л і д у ю ч и * п р и н ц и п у є д и н о ї в і д п о в і д а л ь н о с т і * , к л а с п о в и н е н б у т и м а л и м .
2019-02-04 18:09:04 +02:00
2025-05-01 11:11:48 +02:00
* * П о г а н о : * *
2019-02-04 18:09:04 +02:00
` ` ` ts
class Dashboard {
getLanguage ( ) : string { /* ... */ }
setLanguage ( language : string ) : void { /* ... */ }
showProgress ( ) : void { /* ... */ }
hideProgress ( ) : void { /* ... */ }
isDirty ( ) : boolean { /* ... */ }
disable ( ) : void { /* ... */ }
enable ( ) : void { /* ... */ }
addSubscription ( subscription : Subscription ) : void { /* ... */ }
removeSubscription ( subscription : Subscription ) : void { /* ... */ }
addUser ( user : User ) : void { /* ... */ }
removeUser ( user : User ) : void { /* ... */ }
goToHomePage ( ) : void { /* ... */ }
updateProfile ( details : UserDetails ) : void { /* ... */ }
getVersion ( ) : string { /* ... */ }
// ...
}
` ` `
2025-05-01 11:11:48 +02:00
* * Д о б р е : * *
2019-02-04 18:09:04 +02:00
` ` ` ts
class Dashboard {
disable ( ) : void { /* ... */ }
enable ( ) : void { /* ... */ }
getVersion ( ) : string { /* ... */ }
}
2025-05-01 11:11:48 +02:00
// розділіть відповідальності, переміщуючи решту методів до інших класів
2019-02-04 18:09:04 +02:00
// ...
` ` `
2025-05-01 11:13:28 +02:00
* * [ ⬆ п о в е р н у т и с я д о з м і с т у ] ( # table - of - contents ) * *
2019-02-04 18:09:04 +02:00
2025-05-01 11:11:48 +02:00
# # # В и с о к а з г у р т о в а н і с т ь і н и з ь к а з в ' я з н і с т ь
2019-02-04 18:09:04 +02:00
2025-05-01 11:11:48 +02:00
З г у р т о в а н і с т ь в и з н а ч а є с т у п і н ь з в ' я з к у м і ж ч л е н а м и к л а с у . В і д е а л і в с і п о л я в к л а с і п о в и н н і в и к о р и с т о в у в а т и с я к о ж н и м м е т о д о м .
Т о д і м и к а ж е м о , щ о к л а с є * м а к с и м а л ь н о з г у р т о в а н и м * . Н а п р а к т и ц і , о д н а к , ц е н е з а в ж д и м о ж л и в о і н а в і т ь н е з а в ж д и р е к о м е н д у є т ь с я . П р о т е в а р т о в і д д а в а т и п е р е в а г у в и с о к і й з г у р т о в а н о с т і .
2019-02-04 18:18:27 +02:00
2025-05-01 11:11:48 +02:00
З в 'язність відноситься до того, наскільки пов' я з а н і а б о з а л е ж н і о д и н в і д о д н о г о д в а к л а с и . К л а с и в в а ж а ю т ь с я с л а б о з в ' я з а н и м и , я к щ о з м і н и в о д н о м у з н и х н е в п л и в а ю т ь н а і н ш и й .
2019-02-04 18:09:04 +02:00
2025-05-01 11:11:48 +02:00
Х о р о ш и й д и з а й н п р о г р а м н о г о з а б е з п е ч е н н я м а є * * в и с о к у з г у р т о в а н і с т ь * * і * * н и з ь к у з в ' я з н і с т ь * * .
2019-02-04 18:09:04 +02:00
2025-05-01 11:11:48 +02:00
* * П о г а н о : * *
2019-02-04 18:09:04 +02:00
` ` ` ts
class UserManager {
2025-05-01 11:11:48 +02:00
// Погано: кожна приватна змінна використовується однією а б о іншою групою методів.
// Це ясно свідчить про те, що клас має більше однієї відповідальності.
// Якщо мені потрібно лише створити сервіс для отримання транзакцій для користувача,
// мене все одно змушують передавати екземпляр `emailSender`.
2019-02-04 18:09:04 +02:00
constructor (
private readonly db : Database ,
private readonly emailSender : EmailSender ) {
}
async getUser ( id : number ) : Promise < User > {
2019-02-06 10:43:37 +02:00
return await db . users . findOne ( { id } ) ;
2019-02-04 18:09:04 +02:00
}
async getTransactions ( userId : number ) : Promise < Transaction [ ] > {
2019-02-06 10:43:37 +02:00
return await db . transactions . find ( { userId } ) ;
2019-02-04 18:09:04 +02:00
}
async sendGreeting ( ) : Promise < void > {
await emailSender . send ( 'Welcome!' ) ;
}
async sendNotification ( text : string ) : Promise < void > {
await emailSender . send ( text ) ;
}
async sendNewsletter ( ) : Promise < void > {
// ...
}
}
` ` `
2025-05-01 11:11:48 +02:00
* * Д о б р е : * *
2019-02-04 18:09:04 +02:00
` ` ` ts
class UserService {
constructor ( private readonly db : Database ) {
}
async getUser ( id : number ) : Promise < User > {
2019-02-07 21:53:16 +02:00
return await this . db . users . findOne ( { id } ) ;
2019-02-04 18:09:04 +02:00
}
async getTransactions ( userId : number ) : Promise < Transaction [ ] > {
2019-02-07 21:53:16 +02:00
return await this . db . transactions . find ( { userId } ) ;
2019-02-04 18:09:04 +02:00
}
}
class UserNotifier {
constructor ( private readonly emailSender : EmailSender ) {
}
async sendGreeting ( ) : Promise < void > {
2019-02-07 21:53:16 +02:00
await this . emailSender . send ( 'Welcome!' ) ;
2019-02-04 18:09:04 +02:00
}
async sendNotification ( text : string ) : Promise < void > {
2019-02-07 21:53:16 +02:00
await this . emailSender . send ( text ) ;
2019-02-04 18:09:04 +02:00
}
async sendNewsletter ( ) : Promise < void > {
// ...
}
}
` ` `
2025-05-01 11:13:28 +02:00
* * [ ⬆ п о в е р н у т и с я д о з м і с т у ] ( # table - of - contents ) * *
2019-02-04 18:09:04 +02:00
2025-05-01 11:11:48 +02:00
# # # В і д д а в а й т е п е р е в а г у к о м п о з и ц і ї п е р е д у с п а д к у в а н н я м
2019-02-04 18:09:04 +02:00
2025-05-01 11:11:48 +02:00
Я к в і д о м о з а з н а ч е н о в [ Design Patterns ] ( https : //en.wikipedia.org/wiki/Design_Patterns) від Gang of Four, ви повинні *віддавати перевагу композиції перед успадкуванням*, де це можливо. Є багато вагомих причин використовувати успадкування і багато вагомих причин використовувати композицію. Головна ідея цієї максими полягає в тому, що якщо ваш розум інстинктивно тяжіє до успадкування, спробуйте подумати, чи композиція може краще змоделювати вашу проблему. У деяких випадках це можливо.
2019-02-04 18:09:04 +02:00
2025-05-01 11:11:48 +02:00
В и м о ж е т е з а п и т а т и , "коли я повинен використовувати успадкування?" Ц е з а л е ж и т ь в і д в а ш о ї к о н к р е т н о ї п р о б л е м и , а л е о с ь г і д н и й с п и с о к в и п а д к і в , к о л и у с п а д к у в а н н я м а є б і л ь ш е с е н с у , н і ж к о м п о з и ц і я :
2019-02-04 18:09:04 +02:00
2025-05-01 11:11:48 +02:00
1 . В а ш е у с п а д к у в а н н я п р е д с т а в л я є в і д н о с и н и "є" ( is - a ) , а н е "має" ( has - a ) ( Л ю д и н а - > Т в а р и н а п р о т и К о р и с т у в а ч - > Д а н і к о р и с т у в а ч а ) .
2019-02-04 18:09:04 +02:00
2025-05-01 11:11:48 +02:00
2 . В и м о ж е т е п о в т о р н о в и к о р и с т о в у в а т и к о д з б а з о в и х к л а с і в ( Л ю д и м о ж у т ь р у х а т и с я , я к в с і т в а р и н и ) .
2019-02-04 18:09:04 +02:00
2025-05-01 11:11:48 +02:00
3 . В и х о ч е т е в н о с и т и г л о б а л ь н і з м і н и в п о х і д н і к л а с и , з м і н ю ю ч и б а з о в и й к л а с ( З м і н и т и в и т р а т и к а л о р і й у с і х т в а р и н п і д ч а с р у х у ) .
2019-02-04 18:09:04 +02:00
2025-05-01 11:11:48 +02:00
* * П о г а н о : * *
2019-02-04 18:09:04 +02:00
` ` ` ts
class Employee {
constructor (
2019-02-06 09:57:52 +02:00
private readonly name : string ,
private readonly email : string ) {
2019-02-04 18:09:04 +02:00
}
// ...
}
2025-05-01 11:11:48 +02:00
// Погано, тому що у працівників "є" податкові дані. EmployeeTaxData не є типом Employee
2019-02-04 18:09:04 +02:00
class EmployeeTaxData extends Employee {
constructor (
2019-02-06 09:57:52 +02:00
name : string ,
2019-02-06 10:43:37 +02:00
email : string ,
2019-02-06 09:57:52 +02:00
private readonly ssn : string ,
2019-02-04 18:09:04 +02:00
private readonly salary : number ) {
super ( name , email ) ;
}
// ...
}
` ` `
2025-05-01 11:11:48 +02:00
* * Д о б р е : * *
2019-02-04 18:09:04 +02:00
` ` ` ts
class Employee {
private taxData : EmployeeTaxData ;
constructor (
2019-02-06 09:57:52 +02:00
private readonly name : string ,
private readonly email : string ) {
2019-02-04 18:09:04 +02:00
}
setTaxData ( ssn : string , salary : number ) : Employee {
this . taxData = new EmployeeTaxData ( ssn , salary ) ;
return this ;
}
// ...
}
class EmployeeTaxData {
constructor (
2019-02-12 08:40:50 +02:00
public readonly ssn : string ,
2019-02-04 18:09:04 +02:00
public readonly salary : number ) {
}
// ...
}
` ` `
2025-05-01 11:13:28 +02:00
* * [ ⬆ п о в е р н у т и с я д о з м і с т у ] ( # table - of - contents ) * *
2019-02-04 18:09:04 +02:00
2025-05-01 11:11:48 +02:00
# # # В и к о р и с т о в у й т е л а н ц ю ж о к м е т о д і в
2019-02-04 18:09:04 +02:00
2025-05-01 11:11:48 +02:00
Ц е й п а т е р н д у ж е к о р и с н и й і ч а с т о в и к о р и с т о в у є т ь с я в б а г а т ь о х б і б л і о т е к а х . В і н д о з в о л я є в а ш о м у к о д у б у т и в и р а з н и м і м е н ш б а г а т о с л і в н и м . З ц і є ї п р и ч и н и в и к о р и с т о в у й т е л а н ц ю ж к и м е т о д і в і п о д и в і т ь с я , н а с к і л ь к и ч и с т и м б у д е в а ш к о д .
2019-02-04 18:09:04 +02:00
2025-05-01 11:11:48 +02:00
* * П о г а н о : * *
2019-02-04 18:09:04 +02:00
` ` ` ts
2019-02-05 08:51:37 +02:00
class QueryBuilder {
2019-02-04 18:09:04 +02:00
private collection : string ;
private pageNumber : number = 1 ;
private itemsPerPage : number = 100 ;
private orderByFields : string [ ] = [ ] ;
from ( collection : string ) : void {
this . collection = collection ;
}
page ( number : number , itemsPerPage : number = 100 ) : void {
this . pageNumber = number ;
this . itemsPerPage = itemsPerPage ;
}
orderBy ( . . . fields : string [ ] ) : void {
this . orderByFields = fields ;
}
2019-02-05 08:51:37 +02:00
build ( ) : Query {
2019-02-04 18:09:04 +02:00
// ...
}
}
// ...
2019-02-06 09:57:52 +02:00
const queryBuilder = new QueryBuilder ( ) ;
queryBuilder . from ( 'users' ) ;
queryBuilder . page ( 1 , 100 ) ;
queryBuilder . orderBy ( 'firstName' , 'lastName' ) ;
2019-02-04 18:09:04 +02:00
2019-02-05 08:51:37 +02:00
const query = queryBuilder . build ( ) ;
2019-02-04 18:09:04 +02:00
` ` `
2025-05-01 11:11:48 +02:00
* * Д о б р е : * *
2019-02-04 18:09:04 +02:00
` ` ` ts
2019-02-05 08:51:37 +02:00
class QueryBuilder {
2019-02-04 18:09:04 +02:00
private collection : string ;
private pageNumber : number = 1 ;
private itemsPerPage : number = 100 ;
private orderByFields : string [ ] = [ ] ;
2019-02-05 08:51:37 +02:00
from ( collection : string ) : this {
2019-02-04 18:09:04 +02:00
this . collection = collection ;
return this ;
}
2019-02-05 08:51:37 +02:00
page ( number : number , itemsPerPage : number = 100 ) : this {
2019-02-04 18:09:04 +02:00
this . pageNumber = number ;
this . itemsPerPage = itemsPerPage ;
return this ;
}
2019-02-05 08:51:37 +02:00
orderBy ( . . . fields : string [ ] ) : this {
2019-02-04 18:09:04 +02:00
this . orderByFields = fields ;
return this ;
}
2019-02-05 08:51:37 +02:00
build ( ) : Query {
2019-02-04 18:09:04 +02:00
// ...
}
}
// ...
2019-02-05 08:51:37 +02:00
const query = new QueryBuilder ( )
2019-02-04 18:09:04 +02:00
. from ( 'users' )
. page ( 1 , 100 )
. orderBy ( 'firstName' , 'lastName' )
2019-02-05 08:51:37 +02:00
. build ( ) ;
2019-02-04 18:09:04 +02:00
` ` `
2025-05-01 11:13:28 +02:00
* * [ ⬆ п о в е р н у т и с я д о з м і с т у ] ( # table - of - contents ) * *
2019-02-04 18:09:04 +02:00
2019-02-04 18:08:52 +02:00
# # SOLID
2025-05-01 11:11:48 +02:00
# # # П р и н ц и п є д и н о ї в і д п о в і д а л ь н о с т і ( SRP )
2019-02-04 18:08:52 +02:00
2025-05-01 11:11:48 +02:00
Я к з а з н а ч е н о в Clean Code , "Ніколи не повинно бути більше однієї причини для зміни класу" . С п о к у с л и в о н а б и т и к л а с в е л и к о ю к і л ь к і с т ю ф у н к ц і о н а л ь н о с т і , я к к о л и в и м о ж е т е в з я т и л и ш е о д н у в а л і з у н а в а ш р е й с . П р о б л е м а в т о м у , щ о в а ш к л а с н е б у д е к о н ц е п т у а л ь н о з г у р т о в а н и м і ц е д а с т ь й о м у б а г а т о п р и ч и н д л я з м і н . З м е н ш е н н я к і л ь к о с т і н е о б х і д н и х з м і н к л а с у в а ж л и в е . Ц е в а ж л и в о , т о м у щ о я к щ о з а н а д т о б а г а т о ф у н к ц і о н а л ь н о с т і в о д н о м у к л а с і і в и з м і н ю є т е ч а с т и н у й о г о , м о ж е б у т и в а ж к о з р о з у м і т и , я к ц е в п л и н е н а і н ш і з а л е ж н і м о д у л і у в а ш о м у к о д о в і й б а з і .
2019-02-04 18:08:52 +02:00
2025-05-01 11:11:48 +02:00
* * П о г а н о : * *
2019-02-04 18:08:52 +02:00
` ` ` ts
class UserSettings {
constructor ( private readonly user : User ) {
}
changeSettings ( settings : UserSettings ) {
if ( this . verifyCredentials ( ) ) {
// ...
}
}
verifyCredentials() {
// ...
}
}
` ` `
2025-05-01 11:11:48 +02:00
* * Д о б р е : * *
2019-02-04 18:08:52 +02:00
` ` ` ts
class UserAuth {
constructor ( private readonly user : User ) {
}
verifyCredentials() {
// ...
}
}
class UserSettings {
private readonly auth : UserAuth ;
constructor ( private readonly user : User ) {
this . auth = new UserAuth ( user ) ;
}
changeSettings ( settings : UserSettings ) {
if ( this . auth . verifyCredentials ( ) ) {
// ...
}
}
}
` ` `
2025-05-01 11:13:28 +02:00
* * [ ⬆ п о в е р н у т и с я д о з м і с т у ] ( # table - of - contents ) * *
2019-02-04 18:08:52 +02:00
2025-05-01 11:11:48 +02:00
# # # П р и н ц и п в і д к р и т о с т і / з а к р и т о с т і ( OCP )
2019-02-04 18:08:52 +02:00
2025-05-01 11:11:48 +02:00
Я к з а з н а ч и в Б е р т р а н М е й є р , "програмні сутності (класи, модулі, функції тощо) повинні бути відкритими для розширення, але закритими для модифікації" . Щ о ц е о з н а ч а є ? Ц е й п р и н ц и п в о с н о в н о м у с т в е р д ж у є , щ о в и п о в и н н і д о з в о л я т и к о р и с т у в а ч а м д о д а в а т и н о в і ф у н к ц і о н а л ь н і м о ж л и в о с т і б е з з м і н и і с н у ю ч о г о к о д у .
2019-02-04 18:08:52 +02:00
2025-05-01 11:11:48 +02:00
* * П о г а н о : * *
2019-02-04 18:08:52 +02:00
` ` ` ts
class AjaxAdapter extends Adapter {
constructor ( ) {
super ( ) ;
}
// ...
}
class NodeAdapter extends Adapter {
constructor ( ) {
super ( ) ;
}
// ...
}
class HttpRequester {
constructor ( private readonly adapter : Adapter ) {
}
async fetch < T > ( url : string ) : Promise < T > {
if ( this . adapter instanceof AjaxAdapter ) {
const response = await makeAjaxCall < T > ( url ) ;
2025-05-01 11:11:48 +02:00
// трансформувати відповідь і повернути
2019-02-04 18:08:52 +02:00
} else if ( this . adapter instanceof NodeAdapter ) {
const response = await makeHttpCall < T > ( url ) ;
2025-05-01 11:11:48 +02:00
// трансформувати відповідь і повернути
2019-02-04 18:08:52 +02:00
}
}
}
function makeAjaxCall < T > ( url : string ) : Promise < T > {
2025-05-01 11:11:48 +02:00
// запит і повернення обіцянки
2019-02-04 18:08:52 +02:00
}
function makeHttpCall < T > ( url : string ) : Promise < T > {
2025-05-01 11:11:48 +02:00
// запит і повернення обіцянки
2019-02-04 18:08:52 +02:00
}
` ` `
2025-05-01 11:11:48 +02:00
* * Д о б р е : * *
2019-02-04 18:08:52 +02:00
` ` ` ts
abstract class Adapter {
abstract async request < T > ( url : string ) : Promise < T > ;
2019-02-06 09:57:52 +02:00
2025-05-01 11:11:48 +02:00
// код, спільний для підкласів ...
2019-02-04 18:08:52 +02:00
}
class AjaxAdapter extends Adapter {
constructor ( ) {
super ( ) ;
}
async request < T > ( url : string ) : Promise < T > {
2025-05-01 11:11:48 +02:00
// запит і повернення обіцянки
2019-02-04 18:08:52 +02:00
}
// ...
}
class NodeAdapter extends Adapter {
constructor ( ) {
super ( ) ;
}
async request < T > ( url : string ) : Promise < T > {
2025-05-01 11:11:48 +02:00
// запит і повернення обіцянки
2019-02-04 18:08:52 +02:00
}
// ...
}
class HttpRequester {
constructor ( private readonly adapter : Adapter ) {
}
async fetch < T > ( url : string ) : Promise < T > {
const response = await this . adapter . request < T > ( url ) ;
2025-05-01 11:11:48 +02:00
// трансформувати відповідь і повернути
2019-02-04 18:08:52 +02:00
}
}
` ` `
2025-05-01 11:13:28 +02:00
* * [ ⬆ п о в е р н у т и с я д о з м і с т у ] ( # table - of - contents ) * *
2019-02-04 18:08:52 +02:00
2025-05-01 11:11:48 +02:00
# # # П р и н ц и п п і д с т а н о в к и Л і с к о в ( LSP )
2019-02-04 18:08:52 +02:00
2025-05-01 11:11:48 +02:00
Ц е с т р а ш н и й т е р м і н д л я д у ж е п р о с т о ї к о н ц е п ц і ї . Ф о р м а л ь н о в і н в и з н а ч а є т ь с я я к "Якщо S є підтипом T, то о б 'єкти типу T можуть бути замінені о б 'єктами типу S (тобто о б 'єкти типу S можуть замінити о б 'єкти типу T) без зміни будь-яких бажаних властивостей цієї програми (коректність, виконувані завдання тощо)" . Ц е щ е с т р а ш н і ш е в и з н а ч е н н я .
2019-02-04 18:08:52 +02:00
2025-05-01 11:11:48 +02:00
Н а й к р а щ е п о я с н е н н я п о л я г а є в т о м у , щ о я к щ о у в а с є б а т ь к і в с ь к и й к л а с і д о ч і р н і й к л а с , т о б а т ь к і в с ь к и й к л а с і д о ч і р н і й к л а с м о ж у т ь б у т и в з а є м о з а м і н н и м и б е з о т р и м а н н я н е п р а в и л ь н и х р е з у л ь т а т і в . Ц е в с е щ е м о ж е б у т и н е з р о з у м і л о , т о м у д а в а й т е р о з г л я н е м о к л а с и ч н и й п р и к л а д к в а д р а т а і п р я м о к у т н и к а . М а т е м а т и ч н о к в а д р а т є п р я м о к у т н и к о м , а л е я к щ о в и м о д е л ю є т е й о г о з а д о п о м о г о ю в і д н о с и н "є" ч е р е з у с п а д к у в а н н я , в и ш в и д к о п о т р а п л я є т е в б і д у .
2019-02-04 18:08:52 +02:00
2025-05-01 11:11:48 +02:00
* * П о г а н о : * *
2019-02-04 18:08:52 +02:00
` ` ` ts
class Rectangle {
constructor (
2019-02-06 09:57:52 +02:00
protected width : number = 0 ,
2019-02-04 18:08:52 +02:00
protected height : number = 0 ) {
}
2019-02-06 09:57:52 +02:00
setColor ( color : string ) : this {
2019-02-04 18:08:52 +02:00
// ...
}
render ( area : number ) {
// ...
}
2019-02-06 09:57:52 +02:00
setWidth ( width : number ) : this {
2019-02-04 18:08:52 +02:00
this . width = width ;
2019-02-06 09:57:52 +02:00
return this ;
2019-02-04 18:08:52 +02:00
}
2019-02-06 09:57:52 +02:00
setHeight ( height : number ) : this {
2019-02-04 18:08:52 +02:00
this . height = height ;
2019-02-06 09:57:52 +02:00
return this ;
2019-02-04 18:08:52 +02:00
}
getArea ( ) : number {
return this . width * this . height ;
}
}
class Square extends Rectangle {
2019-02-06 09:57:52 +02:00
setWidth ( width : number ) : this {
2019-02-04 18:08:52 +02:00
this . width = width ;
this . height = width ;
2019-02-06 09:57:52 +02:00
return this ;
2019-02-04 18:08:52 +02:00
}
2019-02-06 09:57:52 +02:00
setHeight ( height : number ) : this {
2019-02-04 18:08:52 +02:00
this . width = height ;
this . height = height ;
2019-02-06 09:57:52 +02:00
return this ;
2019-02-04 18:08:52 +02:00
}
}
function renderLargeRectangles ( rectangles : Rectangle [ ] ) {
rectangles . forEach ( ( rectangle ) = > {
2019-02-06 09:57:52 +02:00
const area = rectangle
. setWidth ( 4 )
. setHeight ( 5 )
2025-05-01 11:11:48 +02:00
. getArea ( ) ; // ПОГАНО: Повертає 25 для Square. Повинно бути 20.
2019-02-04 18:08:52 +02:00
rectangle . render ( area ) ;
} ) ;
}
const rectangles = [ new Rectangle ( ) , new Rectangle ( ) , new Square ( ) ] ;
renderLargeRectangles ( rectangles ) ;
` ` `
2025-05-01 11:11:48 +02:00
* * Д о б р е : * *
2019-02-04 18:08:52 +02:00
` ` ` ts
abstract class Shape {
2019-02-06 09:57:52 +02:00
setColor ( color : string ) : this {
2019-02-04 18:08:52 +02:00
// ...
}
render ( area : number ) {
// ...
}
abstract getArea ( ) : number ;
}
class Rectangle extends Shape {
constructor (
2019-02-06 09:57:52 +02:00
private readonly width = 0 ,
2019-02-04 18:08:52 +02:00
private readonly height = 0 ) {
super ( ) ;
}
getArea ( ) : number {
return this . width * this . height ;
}
}
class Square extends Shape {
constructor ( private readonly length : number ) {
super ( ) ;
}
getArea ( ) : number {
return this . length * this . length ;
}
}
function renderLargeShapes ( shapes : Shape [ ] ) {
shapes . forEach ( ( shape ) = > {
const area = shape . getArea ( ) ;
shape . render ( area ) ;
} ) ;
}
const shapes = [ new Rectangle ( 4 , 5 ) , new Rectangle ( 4 , 5 ) , new Square ( 5 ) ] ;
renderLargeShapes ( shapes ) ;
` ` `
2025-05-01 11:13:28 +02:00
* * [ ⬆ п о в е р н у т и с я д о з м і с т у ] ( # table - of - contents ) * *
2019-02-04 18:08:52 +02:00
2025-05-01 11:11:48 +02:00
# # # П р и н ц и п р о з д і л е н н я і н т е р ф е й с у ( ISP )
2019-02-04 18:08:52 +02:00
2025-05-01 11:11:48 +02:00
ISP с т в е р д ж у є , щ о "Клієнти не повинні бути змушені залежати від інтерфейсів, які вони не використовують" . Ц е й п р и н ц и п д у ж е п о в ' я з а н и й з п р и н ц и п о м є д и н о ї в і д п о в і д а л ь н о с т і .
Щ о ц е д і й с н о о з н а ч а є , т а к ц е т е , щ о в и з а в ж д и п о в и н н і п р о е к т у в а т и с в о ї а б с т р а к ц і ї т а к и м ч и н о м , щ о б к л і є н т и , я к і в и к о р и с т о в у ю т ь в і д к р и т і м е т о д и , н е о т р и м у в а л и в е с ь п и р і г . Ц е т а к о ж в к л ю ч а є в с е б е н а к л а д а н н я н а к л і є н т і в т я г а р я р е а л і з а ц і ї м е т о д і в , я к і ї м н а с п р а в д і н е п о т р і б н і .
2019-02-04 18:08:52 +02:00
2025-05-01 11:11:48 +02:00
* * П о г а н о : * *
2019-02-04 18:08:52 +02:00
` ` ` ts
2019-02-06 10:40:08 +02:00
interface SmartPrinter {
2019-02-04 18:08:52 +02:00
print ( ) ;
fax ( ) ;
scan ( ) ;
}
2019-02-06 10:40:08 +02:00
class AllInOnePrinter implements SmartPrinter {
2019-02-04 18:08:52 +02:00
print() {
// ...
}
fax() {
// ...
}
scan() {
// ...
}
}
2019-02-06 10:40:08 +02:00
class EconomicPrinter implements SmartPrinter {
2019-02-04 18:08:52 +02:00
print() {
// ...
}
fax() {
throw new Error ( 'Fax not supported.' ) ;
}
scan() {
throw new Error ( 'Scan not supported.' ) ;
}
}
` ` `
2025-05-01 11:11:48 +02:00
* * Д о б р е : * *
2019-02-04 18:08:52 +02:00
` ` ` ts
2019-02-06 10:40:08 +02:00
interface Printer {
2019-02-04 18:08:52 +02:00
print ( ) ;
}
2019-02-06 10:40:08 +02:00
interface Fax {
2019-02-04 18:08:52 +02:00
fax ( ) ;
}
2019-02-06 10:40:08 +02:00
interface Scanner {
2019-02-04 18:08:52 +02:00
scan ( ) ;
}
2019-02-06 10:40:08 +02:00
class AllInOnePrinter implements Printer , Fax , Scanner {
2019-02-04 18:08:52 +02:00
print() {
// ...
}
fax() {
// ...
}
scan() {
// ...
}
}
2019-02-06 10:40:08 +02:00
class EconomicPrinter implements Printer {
2019-02-04 18:08:52 +02:00
print() {
// ...
}
}
` ` `
2025-05-01 11:13:28 +02:00
* * [ ⬆ п о в е р н у т и с я д о з м і с т у ] ( # table - of - contents ) * *
2019-02-04 18:08:52 +02:00
2025-05-01 11:11:48 +02:00
# # # П р и н ц и п і н в е р с і ї з а л е ж н о с т е й ( DIP )
2019-02-04 18:08:52 +02:00
2025-05-01 11:11:48 +02:00
Ц е й п р и н ц и п с т в е р д ж у є д в і с у т т є в і р е ч і :
2019-02-04 18:08:52 +02:00
2025-05-01 11:11:48 +02:00
1 . М о д у л і в и с о к о г о р і в н я н е п о в и н н і з а л е ж а т и в і д м о д у л і в н и з ь к о г о р і в н я . О б и д в а п о в и н н і з а л е ж а т и в і д а б с т р а к ц і й .
2019-02-04 18:08:52 +02:00
2025-05-01 11:11:48 +02:00
2 . А б с т р а к ц і ї н е п о в и н н і з а л е ж а т и в і д д е т а л е й . Д е т а л і п о в и н н і з а л е ж а т и в і д а б с т р а к ц і й .
2019-02-04 18:08:52 +02:00
2025-05-01 11:11:48 +02:00
Ц е м о ж е б у т и в а ж к о з р о з у м і т и с п о ч а т к у , а л е я к щ о в и п р а ц ю в а л и з Angular , в и б а ч и л и р е а л і з а ц і ю ц ь о г о п р и н ц и п у у в и г л я д і в п р о в а д ж е н н я з а л е ж н о с т е й ( DI ) . Х о ч а ц е н е і д е н т и ч н і к о н ц е п ц і ї , DIP у т р и м у є м о д у л і в и с о к о г о р і в н я в і д з н а н н я д е т а л е й ї х н і х м о д у л і в н и з ь к о г о р і в н я т а ї х н а л а ш т у в а н н я . Ц е м о ж н а д о с я г т и ч е р е з DI . В е л и ч е з н о ю п е р е в а г о ю ц ь о г о є з м е н ш е н н я з в 'язку між модулями. Зв' я з у в а н н я - ц е д у ж е п о г а н а с х е м а р о з р о б к и , о с к і л ь к и в о н а р о б и т ь в а ш к о д в а ж к и м д л я р е ф а к т о р и н г у .
DIP з а з в и ч а й д о с я г а є т ь с я з а д о п о м о г о ю к о н т е й н е р а і н в е р с і ї у п р а в л і н н я ( IoC ) . П р и к л а д о м п о т у ж н о г о IoC - к о н т е й н е р а д л я TypeScript є [ InversifyJs ] ( https : //www.npmjs.com/package/inversify)
2019-02-04 18:08:52 +02:00
2025-05-01 11:11:48 +02:00
* * П о г а н о : * *
2019-02-04 18:08:52 +02:00
` ` ` ts
import { readFile as readFileCb } from 'fs' ;
import { promisify } from 'util' ;
const readFile = promisify ( readFileCb ) ;
type ReportData = {
// ..
}
class XmlFormatter {
parse < T > ( content : string ) : T {
2025-05-01 11:11:48 +02:00
// Перетворює рядок XML на о б 'єкт T
2019-02-04 18:08:52 +02:00
}
}
class ReportReader {
2025-05-01 11:11:48 +02:00
// ПОГАНО: Ми створили залежність від конкретної реалізації запиту.
// Нам слід просто зробити так, щоб ReportReader залежав від методу parse: `parse`
2019-02-04 18:08:52 +02:00
private readonly formatter = new XmlFormatter ( ) ;
async read ( path : string ) : Promise < ReportData > {
const text = await readFile ( path , 'UTF8' ) ;
return this . formatter . parse < ReportData > ( text ) ;
}
}
// ...
const reader = new ReportReader ( ) ;
2021-11-12 23:36:58 +01:00
const report = await reader . read ( 'report.xml' ) ;
2019-02-04 18:08:52 +02:00
` ` `
2025-05-01 11:11:48 +02:00
* * Д о б р е : * *
2019-02-04 18:08:52 +02:00
` ` ` ts
import { readFile as readFileCb } from 'fs' ;
import { promisify } from 'util' ;
const readFile = promisify ( readFileCb ) ;
type ReportData = {
// ..
}
interface Formatter {
parse < T > ( content : string ) : T ;
}
class XmlFormatter implements Formatter {
parse < T > ( content : string ) : T {
2025-05-01 11:11:48 +02:00
// Перетворює рядок XML на о б 'єкт T
2019-02-04 18:08:52 +02:00
}
}
class JsonFormatter implements Formatter {
parse < T > ( content : string ) : T {
2025-05-01 11:11:48 +02:00
// Перетворює рядок JSON на о б 'єкт T
2019-02-04 18:08:52 +02:00
}
}
class ReportReader {
2019-02-06 10:43:37 +02:00
constructor ( private readonly formatter : Formatter ) {
2019-02-04 18:08:52 +02:00
}
async read ( path : string ) : Promise < ReportData > {
const text = await readFile ( path , 'UTF8' ) ;
return this . formatter . parse < ReportData > ( text ) ;
}
}
// ...
const reader = new ReportReader ( new XmlFormatter ( ) ) ;
2021-11-12 23:36:58 +01:00
const report = await reader . read ( 'report.xml' ) ;
2019-02-04 18:08:52 +02:00
2025-05-01 11:11:48 +02:00
// а б о якщо нам потрібно прочитати json звіт
2019-02-04 18:08:52 +02:00
const reader = new ReportReader ( new JsonFormatter ( ) ) ;
2021-11-12 23:36:58 +01:00
const report = await reader . read ( 'report.json' ) ;
2019-02-04 18:08:52 +02:00
` ` `
2025-05-01 11:13:28 +02:00
* * [ ⬆ п о в е р н у т и с я д о з м і с т у ] ( # table - of - contents ) * *
2019-02-04 18:08:52 +02:00
2025-05-01 11:11:48 +02:00
# # Т е с т у в а н н я
2019-02-04 09:18:53 +02:00
2025-05-01 11:11:48 +02:00
Т е с т у в а н н я є в а ж л и в і ш и м з а д о с т а в к у . Я к щ о у в а с н е м а є т е с т і в а б о ї х н е д о с т а т н ь о , к о ж н о г о р а з у , к о л и в и д о с т а в л я є т е к о д , в и н е б у д е т е в п е в н е н і , щ о н і ч о г о н е з л а м а л и .
В и р і ш е н н я т о г о , щ о с т а н о в и т ь д о с т а т н ю к і л ь к і с т ь , з а л е ж и т ь в і д в а ш о ї к о м а н д и , а л е 100 % п о к р и т т я ( в с і о п е р а т о р и т а г і л к и )
- ц е с п о с і б д о с я г т и д у ж е в и с о к о ї в п е в н е н о с т і т а с п о к о ю р о з р о б н и к і в . Ц е о з н а ч а є , щ о к р і м н а я в н о с т і ч у д о в о г о ф р е й м в о р к у д л я т е с т у в а н н я , в а м т а к о ж п о т р і б н о в и к о р и с т о в у в а т и х о р о ш и й [ і н с т р у м е н т п о к р и т т я ] ( https : //github.com/gotwarlost/istanbul).
2019-02-04 09:18:53 +02:00
2025-05-01 11:11:48 +02:00
Н е м а є в и п р а в д а н н я н е п и с а т и т е с т и . І с н у є [ б а г а т о х о р о ш и х JS - ф р е й м в о р к і в д л я т е с т у в а н н я ] ( http : //jstherightway.org/#testing-tools) з підтримкою типізації для TypeScript, тому знайдіть той, який підходить вашій команді. Коли ви знайдете один, що працює для вашої команди, тоді намагайтеся завжди писати тести для кожної нової функції/модуля, який ви вводите. Якщо ваш переважний метод - це розробка через тестування (TDD), це чудово, але головне - просто переконатися, що ви досягаєте своїх цілей з покриття перед запуском будь-якої функції а б о рефакторингом існуючої.
2019-02-04 09:18:53 +02:00
2025-05-01 11:11:48 +02:00
# # # Т р и з а к о н и TDD
2019-02-04 09:18:53 +02:00
2025-05-01 11:11:48 +02:00
1 . В а м н е д о з в о л я є т ь с я п и с а т и в и р о б н и ч и й к о д , я к щ о ц е н е д л я т о г о , щ о б п р о й т и м о д у л ь н и й т е с т , щ о н е п р о х о д и т ь .
2019-02-04 09:18:53 +02:00
2025-05-01 11:11:48 +02:00
2 . В а м н е д о з в о л я є т ь с я п и с а т и б і л ь ш е м о д у л ь н о г о т е с т у , н і ж д о с т а т н ь о д л я н е в д а ч і , і ; п о м и л к и к о м п і л я ц і ї - ц е н е в д а ч і .
2019-02-04 09:18:53 +02:00
2025-05-01 11:11:48 +02:00
3 . В а м н е д о з в о л я є т ь с я п и с а т и б і л ь ш е в и р о б н и ч о г о к о д у , н і ж д о с т а т н ь о д л я п р о х о д ж е н н я о д н о г о н е в д а л о г о м о д у л ь н о г о т е с т у .
2019-02-04 09:18:53 +02:00
2025-05-01 11:13:28 +02:00
* * [ ⬆ п о в е р н у т и с я д о з м і с т у ] ( # table - of - contents ) * *
2019-02-04 09:18:53 +02:00
2025-05-01 11:11:48 +02:00
# # # П р а в и л а F . I . R . S . T .
2019-02-04 09:18:53 +02:00
2025-05-01 11:11:48 +02:00
Ч и с т і т е с т и п о в и н н і д о т р и м у в а т и с я т а к и х п р а в и л :
2019-02-04 09:18:53 +02:00
2025-05-01 11:11:48 +02:00
- * * Fast * * ( Ш в и д к і ) т е с т и п о в и н н і б у т и ш в и д к и м и , т о м у щ о м и х о ч е м о з а п у с к а т и ї х ч а с т о .
2019-02-04 09:18:53 +02:00
2025-05-01 11:11:48 +02:00
- * * Independent * * ( Н е з а л е ж н і ) т е с т и н е п о в и н н і з а л е ж а т и о д и н в і д о д н о г о . В о н и п о в и н н і д а в а т и о д н а к о в и й р е з у л ь т а т н е з а л е ж н о в і д т о г о , з а п у с к а ю т ь с я в о н и о к р е м о ч и в с і р а з о м у б у д ь - я к о м у п о р я д к у .
2019-02-04 09:18:53 +02:00
2025-05-01 11:11:48 +02:00
- * * Repeatable * * ( П о в т о р ю в а н і ) т е с т и п о в и н н і б у т и п о в т о р ю в а н и м и в б у д ь - я к о м у с е р е д о в и щ і , і н е п о в и н н о б у т и в и п р а в д а н н я , ч о м у в о н и п р о в а л ю ю т ь с я .
2019-02-04 09:18:53 +02:00
2025-05-01 11:11:48 +02:00
- * * Self - Validating * * ( С а м о п е р е в і р о ч н і ) т е с т п о в и н е н в і д п о в і д а т и а б о * П р о й д е н о * , а б о * Н е п р о й д е н о * . В а м н е п о т р і б н о п о р і в н ю в а т и ф а й л и ж у р н а л і в , щ о б в і д п о в і с т и , ч и п р о й ш о в т е с т .
2019-02-04 09:18:53 +02:00
2025-05-01 11:11:48 +02:00
- * * Timely * * ( С в о є ч а с н і ) м о д у л ь н і т е с т и п о в и н н і б у т и н а п и с а н і д о в и р о б н и ч о г о к о д у . Я к щ о в и п и ш е т е т е с т и п і с л я в и р о б н и ч о г о к о д у , в и м о ж е т е в и я в и т и , щ о н а п и с а н н я т е с т і в з а н а д т о с к л а д н е .
2019-02-04 09:18:53 +02:00
2025-05-01 11:13:28 +02:00
* * [ ⬆ п о в е р н у т и с я д о з м і с т у ] ( # table - of - contents ) * *
2019-02-04 09:18:53 +02:00
2025-05-01 11:11:48 +02:00
# # # О д н а к о н ц е п ц і я н а т е с т
2019-02-04 09:18:53 +02:00
2025-05-01 11:11:48 +02:00
Т е с т и т а к о ж п о в и н н і с л і д у в а т и * П р и н ц и п у є д и н о ї в і д п о в і д а л ь н о с т і * . Р о б і т ь л и ш е о д н е т в е р д ж е н н я н а м о д у л ь н и й т е с т .
2019-02-04 09:18:53 +02:00
2025-05-01 11:11:48 +02:00
* * П о г а н о : * *
2019-02-04 09:18:53 +02:00
` ` ` ts
import { assert } from 'chai' ;
describe ( 'AwesomeDate' , ( ) = > {
it ( 'handles date boundaries' , ( ) = > {
let date : AwesomeDate ;
date = new AwesomeDate ( '1/1/2015' ) ;
2019-02-07 21:53:16 +02:00
assert . equal ( '1/31/2015' , date . addDays ( 30 ) ) ;
2019-02-04 09:18:53 +02:00
date = new AwesomeDate ( '2/1/2016' ) ;
2019-02-07 21:53:16 +02:00
assert . equal ( '2/29/2016' , date . addDays ( 28 ) ) ;
2019-02-04 09:18:53 +02:00
date = new AwesomeDate ( '2/1/2015' ) ;
2019-02-07 21:53:16 +02:00
assert . equal ( '3/1/2015' , date . addDays ( 28 ) ) ;
2019-02-04 09:18:53 +02:00
} ) ;
} ) ;
` ` `
2025-05-01 11:11:48 +02:00
* * Д о б р е : * *
2019-02-04 09:18:53 +02:00
` ` ` ts
import { assert } from 'chai' ;
describe ( 'AwesomeDate' , ( ) = > {
it ( 'handles 30-day months' , ( ) = > {
const date = new AwesomeDate ( '1/1/2015' ) ;
2019-02-07 21:53:16 +02:00
assert . equal ( '1/31/2015' , date . addDays ( 30 ) ) ;
2019-02-04 09:18:53 +02:00
} ) ;
it ( 'handles leap year' , ( ) = > {
const date = new AwesomeDate ( '2/1/2016' ) ;
2019-02-07 21:53:16 +02:00
assert . equal ( '2/29/2016' , date . addDays ( 28 ) ) ;
2019-02-04 09:18:53 +02:00
} ) ;
it ( 'handles non-leap year' , ( ) = > {
const date = new AwesomeDate ( '2/1/2015' ) ;
2019-02-07 21:53:16 +02:00
assert . equal ( '3/1/2015' , date . addDays ( 28 ) ) ;
2019-02-04 09:18:53 +02:00
} ) ;
} ) ;
` ` `
2025-05-01 11:13:28 +02:00
* * [ ⬆ п о в е р н у т и с я д о з м і с т у ] ( # table - of - contents ) * *
2019-02-04 09:18:53 +02:00
2025-05-01 11:11:48 +02:00
# # # Н а з в а т е с т у п о в и н н а р о з к р и в а т и й о г о н а м і р
2019-02-04 09:18:53 +02:00
2025-05-01 11:11:48 +02:00
К о л и т е с т н е п р о х о д и т ь , й о г о н а з в а є п е р ш и м п о к а з н и к о м т о г о , щ о м о г л о п і т и н е т а к .
2019-02-04 09:18:53 +02:00
2025-05-01 11:11:48 +02:00
* * П о г а н о : * *
2019-02-04 09:18:53 +02:00
` ` ` ts
describe ( 'Calendar' , ( ) = > {
it ( '2/29/2020' , ( ) = > {
// ...
} ) ;
it ( 'throws' , ( ) = > {
// ...
} ) ;
} ) ;
` ` `
2025-05-01 11:11:48 +02:00
* * Д о б р е : * *
2019-02-04 09:18:53 +02:00
` ` ` ts
describe ( 'Calendar' , ( ) = > {
it ( 'should handle leap year' , ( ) = > {
// ...
} ) ;
it ( 'should throw when format is invalid' , ( ) = > {
// ...
} ) ;
} ) ;
` ` `
2025-05-01 11:13:28 +02:00
* * [ ⬆ п о в е р н у т и с я д о з м і с т у ] ( # table - of - contents ) * *
2019-02-04 09:18:53 +02:00
2025-05-01 11:11:48 +02:00
# # А с и н х р о н н і с т ь
2019-01-29 17:25:00 +02:00
2025-05-01 11:11:48 +02:00
# # # П е р е в а г а о б і ц я н о к ( promises ) п е р е д з в о р о т н и м и в и к л и к а м и ( callbacks )
2019-01-29 17:25:00 +02:00
2025-05-01 11:11:48 +02:00
З в о р о т н і в и к л и к и н е є ч и с т и м и , і в о н и с п р и ч и н я ю т ь н а д м і р н у к і л ь к і с т ь в к л а д е н о с т і * ( п е к л о з в о р о т н и х в и к л и к і в ) * .
І с н у ю т ь у т и л і т и , я к і п е р е т в о р ю ю т ь і с н у ю ч і ф у н к ц і ї , щ о в и к о р и с т о в у ю т ь з в о р о т н і в и к л и к и , н а в е р с і ю , я к а п о в е р т а є о б і ц я н к и
( д л я Node . js д и в . [ ` util.promisify ` ] ( https : //nodejs.org/dist/latest-v8.x/docs/api/util.html#util_util_promisify_original), для загального призначення див. [pify](https://www.npmjs.com/package/pify), [es6-promisify](https://www.npmjs.com/package/es6-promisify))
2019-01-29 17:25:00 +02:00
2025-05-01 11:11:48 +02:00
* * П о г а н о : * *
2019-01-29 17:25:00 +02:00
` ` ` ts
import { get } from 'request' ;
import { writeFile } from 'fs' ;
2019-02-06 10:43:37 +02:00
function downloadPage ( url : string , saveTo : string , callback : ( error : Error , content? : string ) = > void ) {
2019-01-29 17:25:00 +02:00
get ( url , ( error , response ) = > {
if ( error ) {
callback ( error ) ;
} else {
writeFile ( saveTo , response . body , ( error ) = > {
if ( error ) {
callback ( error ) ;
} else {
callback ( null , response . body ) ;
}
} ) ;
}
2019-02-06 10:43:37 +02:00
} ) ;
2019-01-29 17:25:00 +02:00
}
downloadPage ( 'https://en.wikipedia.org/wiki/Robert_Cecil_Martin' , 'article.html' , ( error , content ) = > {
if ( error ) {
console . error ( error ) ;
} else {
console . log ( content ) ;
}
} ) ;
` ` `
2025-05-01 11:11:48 +02:00
* * Д о б р е : * *
2019-01-29 17:25:00 +02:00
` ` ` ts
import { get } from 'request' ;
import { writeFile } from 'fs' ;
import { promisify } from 'util' ;
const write = promisify ( writeFile ) ;
function downloadPage ( url : string , saveTo : string ) : Promise < string > {
return get ( url )
2019-02-06 10:43:37 +02:00
. then ( response = > write ( saveTo , response ) ) ;
2019-01-29 17:25:00 +02:00
}
downloadPage ( 'https://en.wikipedia.org/wiki/Robert_Cecil_Martin' , 'article.html' )
. then ( content = > console . log ( content ) )
. catch ( error = > console . error ( error ) ) ;
` ` `
2025-05-01 11:11:48 +02:00
О б і ц я н к и п і д т р и м у ю т ь к і л ь к а д о п о м і ж н и х м е т о д і в , я к і д о п о м а г а ю т ь з р о б и т и к о д б і л ь ш с т и с л и м :
2019-01-31 10:18:41 +02:00
2025-05-01 11:11:48 +02:00
| Ш а б л о н | О п и с |
2019-01-31 10:18:41 +02:00
| -- -- -- -- -- -- -- -- -- -- -- -- | -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - |
2025-05-01 11:11:48 +02:00
| ` Promise.resolve(value) ` | П е р е т в о р ю є з н а ч е н н я в в и р і ш е н у о б і ц я н к у . |
| ` Promise.reject(error) ` | П е р е т в о р ю є п о м и л к у в в і д х и л е н у о б і ц я н к у . |
| ` Promise.all(promises) ` | П о в е р т а є н о в у о б і ц я н к у , я к а в и к о н у є т ь с я з м а с и в о м з н а ч е н ь в и к о н а н н я д л я п е р е д а н и х о б і ц я н о к а б о в і д х и л я є т ь с я з п р и ч и н о ю п е р ш о ї о б і ц я н к и , я к а в і д х и л я є т ь с я . |
| ` Promise.race(promises) ` | П о в е р т а є н о в у о б і ц я н к у , я к а в и к о н у є т ь с я / в і д х и л я є т ь с я з р е з у л ь т а т о м / п о м и л к о ю п е р ш о ї в р е г у л ь о в а н о ї о б і ц я н к и з м а с и в у п е р е д а н и х о б і ц я н о к . |
2019-01-31 10:18:41 +02:00
2025-05-01 11:11:48 +02:00
` Promise.all ` о с о б л и в о к о р и с н и й , к о л и і с н у є п о т р е б а з а п у с к а т и з а в д а н н я п а р а л е л ь н о . ` Promise.race ` п о л е г ш у є р е а л і з а ц і ю т а к и х р е ч е й , я к т а й м - а у т и д л я о б і ц я н о к .
2019-01-31 10:18:41 +02:00
2025-05-01 11:13:28 +02:00
* * [ ⬆ п о в е р н у т и с я д о з м і с т у ] ( # table - of - contents ) * *
2019-01-29 17:25:00 +02:00
2025-05-01 11:11:48 +02:00
# # # Async / Await щ е ч и с т і ш і з а о б і ц я н к и
2019-01-29 17:25:00 +02:00
2025-05-01 11:11:48 +02:00
З с и н т а к с и с о м ` async ` / ` await ` в и м о ж е т е п и с а т и к о д , я к и й є н а б а г а т о ч и с т і ш и м т а з р о з у м і л і ш и м , н і ж л а н ц ю ж к и о б і ц я н о к . У ф у н к ц і ї з п р е ф і к с о м к л ю ч о в о г о с л о в а ` async ` у в а с є с п о с і б с к а з а т и с е р е д о в и щ у в и к о н а н н я JavaScript п р и з у п и н и т и в и к о н а н н я к о д у н а к л ю ч о в о м у с л о в і ` await ` ( к о л и в о н о в и к о р и с т о в у є т ь с я з о б і ц я н к о ю ) .
2019-01-29 17:25:00 +02:00
2025-05-01 11:11:48 +02:00
* * П о г а н о : * *
2019-01-29 17:25:00 +02:00
` ` ` ts
import { get } from 'request' ;
import { writeFile } from 'fs' ;
import { promisify } from 'util' ;
const write = util . promisify ( writeFile ) ;
function downloadPage ( url : string , saveTo : string ) : Promise < string > {
2019-02-06 10:48:34 +02:00
return get ( url ) . then ( response = > write ( saveTo , response ) ) ;
2019-01-29 17:25:00 +02:00
}
downloadPage ( 'https://en.wikipedia.org/wiki/Robert_Cecil_Martin' , 'article.html' )
. then ( content = > console . log ( content ) )
. catch ( error = > console . error ( error ) ) ;
` ` `
2025-05-01 11:11:48 +02:00
* * Д о б р е : * *
2019-01-29 17:25:00 +02:00
` ` ` ts
import { get } from 'request' ;
import { writeFile } from 'fs' ;
import { promisify } from 'util' ;
const write = promisify ( writeFile ) ;
2022-07-15 13:58:56 +02:00
async function downloadPage ( url : string ) : Promise < string > {
2019-01-29 17:25:00 +02:00
const response = await get ( url ) ;
return response ;
}
2025-05-01 11:11:48 +02:00
// десь в асинхронній функції
2019-01-29 17:25:00 +02:00
try {
2022-07-15 13:58:56 +02:00
const content = await downloadPage ( 'https://en.wikipedia.org/wiki/Robert_Cecil_Martin' ) ;
await write ( 'article.html' , content ) ;
2019-01-29 17:25:00 +02:00
console . log ( content ) ;
} catch ( error ) {
console . error ( error ) ;
}
` ` `
2025-05-01 11:13:28 +02:00
* * [ ⬆ п о в е р н у т и с я д о з м і с т у ] ( # table - of - contents ) * *
2019-02-04 09:18:53 +02:00
2025-05-01 11:11:48 +02:00
# # О б р о б к а п о м и л о к
2019-02-04 09:18:53 +02:00
2025-05-01 11:11:48 +02:00
В и к и н у т і п о м и л к и - ц е х о р о ш а р і ч ! В о н и о з н а ч а ю т ь , щ о с е р е д о в и щ е в и к о н а н н я у с п і ш н о в и з н а ч и л о , к о л и щ о с ь у в а ш і й п р о г р а м і п і ш л о н е т а к , і в о н о п о в і д о м л я є в а м , з у п и н я ю ч и в и к о н а н н я ф у н к ц і ї
в п о т о ч н о м у с т е к у , з а в е р ш у ю ч и п р о ц е с ( у Node ) , т а п о в і д о м л я ю ч и в а с у к о н с о л і з а д о п о м о г о ю с л і д у с т е к у .
2019-02-04 09:18:53 +02:00
2025-05-01 11:11:48 +02:00
# # # З а в ж д и в и к о р и с т о в у й т е Error д л я в и к и д а н н я ч и в і д х и л е н н я
2019-02-04 09:18:53 +02:00
2025-05-01 11:11:48 +02:00
JavaScript , а т а к о ж TypeScript д о з в о л я ю т ь в а м ` throw ` б у д ь - я к и й о б 'єкт. Обіцянка також може бути відхилена з будь-якою причиною о б ' є к т а .
Р е к о м е н д у є т ь с я в и к о р и с т о в у в а т и с и н т а к с и с ` throw ` з т и п о м ` Error ` . Ц е т о м у , щ о в а ш а п о м и л к а м о ж е б у т и п е р е х о п л е н а у к о д і в и щ о г о р і в н я з с и н т а к с и с о м ` catch ` .
Б у л о б д у ж е з а п л у т а н о п е р е х о п и т и т а м т е к с т о в е п о в і д о м л е н н я , і ц е з р о б и л о б [ н а л а г о д ж е н н я б і л ь ш б о л і с н и м ] ( https : //basarat.gitbook.io/typescript/type-system/exceptions#always-use-error).
З т і є ї ж п р и ч и н и в и п о в и н н і в і д х и л я т и о б і ц я н к и з т и п а м и ` Error ` .
2019-02-04 09:18:53 +02:00
2025-05-01 11:11:48 +02:00
* * П о г а н о : * *
2019-02-04 09:18:53 +02:00
` ` ` ts
function calculateTotal ( items : Item [ ] ) : number {
throw 'Not implemented.' ;
}
function get ( ) : Promise < Item [ ] > {
return Promise . reject ( 'Not implemented.' ) ;
}
` ` `
2025-05-01 11:11:48 +02:00
* * Д о б р е : * *
2019-02-04 09:18:53 +02:00
` ` ` ts
function calculateTotal ( items : Item [ ] ) : number {
throw new Error ( 'Not implemented.' ) ;
}
function get ( ) : Promise < Item [ ] > {
return Promise . reject ( new Error ( 'Not implemented.' ) ) ;
}
2025-05-01 11:11:48 +02:00
// а б о еквівалентно до:
2019-02-04 09:18:53 +02:00
async function get ( ) : Promise < Item [ ] > {
throw new Error ( 'Not implemented.' ) ;
}
` ` `
2025-05-01 11:11:48 +02:00
П е р е в а г а в и к о р и с т а н н я т и п і в ` Error ` п о л я г а є в т о м у , щ о в о н и п і д т р и м у ю т ь с я с и н т а к с и с о м ` try/catch/finally ` , і н е я в н о в с і п о м и л к и м а ю т ь в л а с т и в і с т ь ` stack ` , я к а
д у ж е п о т у ж н а д л я н а л а г о д ж е н н я .
І с н у ю т ь т а к о ж і н ш і а л ь т е р н а т и в и , н е в и к о р и с т о в у в а т и с и н т а к с и с ` throw ` , а з а м і с т ь ц ь о г о з а в ж д и п о в е р т а т и к о р и с т у в а ц ь к і о б ' є к т и п о м и л о к . TypeScript п о л е г ш у є ц е . Р о з г л я н ь т е н а с т у п н и й п р и к л а д :
2019-02-05 14:22:02 +02:00
` ` ` ts
2019-02-05 17:21:31 +02:00
type Result < R > = { isError : false , value : R } ;
type Failure < E > = { isError : true , error : E } ;
type Failable < R , E > = Result < R > | Failure < E > ;
2019-02-05 14:22:02 +02:00
function calculateTotal ( items : Item [ ] ) : Failable < number , 'empty' > {
if ( items . length === 0 ) {
return { isError : true , error : 'empty' } ;
}
// ...
return { isError : false , value : 42 } ;
}
` ` `
2025-05-01 11:11:48 +02:00
Д л я д е т а л ь н о г о п о я с н е н н я ц і є ї і д е ї з в е р н і т ь с я д о [ о р и г і н а л ь н о г о п о с т у ] ( https : //medium.com/@dhruvrajvanshi/making-exceptions-type-safe-in-typescript-c4d200ee78e9).
2019-02-05 14:22:02 +02:00
2025-05-01 11:13:28 +02:00
* * [ ⬆ п о в е р н у т и с я д о з м і с т у ] ( # table - of - contents ) * *
2019-02-04 09:18:53 +02:00
2025-05-01 11:11:48 +02:00
# # # Н е і г н о р у й т е п е р е х о п л е н і п о м и л к и
2019-02-04 09:18:53 +02:00
2025-05-01 11:11:48 +02:00
Н і ч о г о н е р о б и т и з п е р е х о п л е н о ю п о м и л к о ю н е д а є в а м м о ж л и в о с т і в и п р а в и т и а б о р е а г у в а т и н а ц ю п о м и л к у . З а п и с п о м и л к и в к о н с о л ь ( ` console.log ` ) н е н а б а г а т о к р а щ е , о с к і л ь к и ч а с т о в о н а м о ж е г у б и т и с я в м о р і р е ч е й , в и в е д е н и х н а к о н с о л ь . Я к щ о в и о б г о р т а є т е б у д ь - я к и й ф р а г м е н т к о д у в ` try/catch ` , ц е о з н а ч а є , щ о в и д у м а є т е , щ о т а м м о ж е в и н и к н у т и п о м и л к а , і т о м у у в а с п о в и н е н б у т и п л а н а б о ш л я х к о д у д л я в и п а д к у , к о л и в о н а в и н и к а є .
2019-02-04 09:18:53 +02:00
2025-05-01 11:11:48 +02:00
* * П о г а н о : * *
2019-02-04 09:18:53 +02:00
` ` ` ts
try {
functionThatMightThrow ( ) ;
} catch ( error ) {
console . log ( error ) ;
}
2025-05-01 11:11:48 +02:00
// а б о ще гірше
2019-02-04 09:18:53 +02:00
try {
functionThatMightThrow ( ) ;
} catch ( error ) {
2025-05-01 11:11:48 +02:00
// ігнорувати помилку
2019-02-04 09:18:53 +02:00
}
` ` `
2025-05-01 11:11:48 +02:00
* * Д о б р е : * *
2019-02-04 09:18:53 +02:00
` ` ` ts
import { logger } from './logging'
try {
functionThatMightThrow ( ) ;
} catch ( error ) {
logger . log ( error ) ;
}
` ` `
2025-05-01 11:13:28 +02:00
* * [ ⬆ п о в е р н у т и с я д о з м і с т у ] ( # table - of - contents ) * *
2019-02-04 09:18:53 +02:00
2025-05-01 11:11:48 +02:00
# # # Н е і г н о р у й т е в і д х и л е н і о б і ц я н к и
2019-02-04 09:18:53 +02:00
2025-05-01 11:11:48 +02:00
З т і є ї ж п р и ч и н и в и н е п о в и н н і і г н о р у в а т и п е р е х о п л е н і п о м и л к и з ` try/catch ` .
2019-02-04 09:18:53 +02:00
2025-05-01 11:11:48 +02:00
* * П о г а н о : * *
2019-02-04 09:18:53 +02:00
` ` ` ts
getUser ( )
. then ( ( user : User ) = > {
return sendEmail ( user . email , 'Welcome!' ) ;
} )
. catch ( ( error ) = > {
console . log ( error ) ;
} ) ;
` ` `
2025-05-01 11:11:48 +02:00
* * Д о б р е : * *
2019-02-04 09:18:53 +02:00
` ` ` ts
import { logger } from './logging'
getUser ( )
. then ( ( user : User ) = > {
return sendEmail ( user . email , 'Welcome!' ) ;
} )
. catch ( ( error ) = > {
logger . log ( error ) ;
} ) ;
2025-05-01 11:11:48 +02:00
// а б о використовуючи синтаксис async/await:
2019-02-04 09:18:53 +02:00
try {
const user = await getUser ( ) ;
await sendEmail ( user . email , 'Welcome!' ) ;
} catch ( error ) {
logger . log ( error ) ;
}
` ` `
2025-05-01 11:13:28 +02:00
* * [ ⬆ п о в е р н у т и с я д о з м і с т у ] ( # table - of - contents ) * *
2019-02-04 09:18:53 +02:00
2025-05-01 11:11:48 +02:00
# # Ф о р м а т у в а н н я
2019-02-04 09:16:01 +02:00
2025-05-01 11:11:48 +02:00
Ф о р м а т у в а н н я є с у б ' є к т и в н и м . Я к і б а г а т о п р а в и л т у т , н е м а є ж о р с т к о г о і ш в и д к о г о п р а в и л а , я к о г о в и п о в и н н і д о т р и м у в а т и с я . Г о л о в н а т о ч к а - * Н Е С П Е Р Е Ч А Т И С Я * п р о ф о р м а т у в а н н я . І с н у є б е з л і ч і н с т р у м е н т і в д л я а в т о м а т и з а ц і ї ц ь о г о . В и к о р и с т о в у й т е о д и н ! Ц е м а р н у в а н н я ч а с у і г р о ш е й д л я і н ж е н е р і в с п е р е ч а т и с я п р о ф о р м а т у в а н н я . З а г а л ь н е п р а в и л о , я к о г о с л і д д о т р и м у в а т и с я , - * з б е р і г а т и п о с л і д о в н і п р а в и л а ф о р м а т у в а н н я * .
2019-02-04 09:16:01 +02:00
2025-05-01 11:11:48 +02:00
Д л я TypeScript і с н у є п о т у ж н и й і н с т р у м е н т п і д н а з в о ю [ ESLint ] ( https : //typescript-eslint.io/). Це інструмент статичного аналізу, який може допомогти вам кардинально покращити читабельність та обслуговуваність вашого коду. Існують готові до використання конфігурації ESLint, на які ви можете посилатися у своїх проектах:
2019-02-04 09:16:01 +02:00
2025-05-01 11:11:48 +02:00
- [ ESLint Config Airbnb ] ( https : //www.npmjs.com/package/eslint-config-airbnb-typescript) - Стиль Airbnb
2019-02-04 09:16:01 +02:00
2025-05-01 11:11:48 +02:00
- [ ESLint Base Style Config ] ( https : //www.npmjs.com/package/eslint-plugin-base-style-config) - Н а б і р основних правил ESLint для JS, TS та React
2019-02-04 09:16:01 +02:00
2025-05-01 11:11:48 +02:00
- [ ESLint + Prettier ] ( https : //www.npmjs.com/package/eslint-config-prettier) - правила lint для форматера коду [Prettier](https://github.com/prettier/prettier)
2019-02-04 09:22:16 +02:00
2025-05-01 11:11:48 +02:00
З в е р н і т ь с я т а к о ж д о ц ь о г о ч у д о в о г о д ж е р е л а [ TypeScript StyleGuide and Coding Conventions ] ( https : //basarat.gitbook.io/typescript/styleguide).
2019-02-04 09:16:01 +02:00
2025-05-01 11:11:48 +02:00
# # # М і г р а ц і я з TSLint н а ESLint
2019-02-04 09:18:53 +02:00
2025-05-01 11:11:48 +02:00
Я к щ о в и ш у к а є т е д о п о м о г у в м і г р а ц і ї з TSLint н а ESLint , в и м о ж е т е п е р е в і р и т и ц е й п р о е к т : < https : //github.com/typescript-eslint/tslint-to-eslint-config>
2019-02-04 09:16:01 +02:00
2025-05-01 11:11:48 +02:00
# # # В и к о р и с т о в у й т е п о с л і д о в н у к а п і т а л і з а ц і ю
2019-02-04 09:16:01 +02:00
2025-05-01 11:11:48 +02:00
К а п і т а л і з а ц і я р о з п о в і д а є в а м б а г а т о п р о в а ш і з м і н н і , ф у н к ц і ї т о щ о . Ц і п р а в и л а є с у б ' є к т и в н и м и , т о м у в а ш а к о м а н д а м о ж е в и б р а т и т е , щ о з а х о ч е . С у т ь в т о м у , щ о н е з а л е ж н о в і д т о г о , щ о в и в с і в и б е р е т е , п р о с т о * б у д ь т е п о с л і д о в н и м и * .
2019-02-04 09:16:01 +02:00
2025-05-01 11:11:48 +02:00
* * П о г а н о : * *
2019-02-04 09:16:01 +02:00
` ` ` ts
const DAYS_IN_WEEK = 7 ;
const daysInMonth = 30 ;
const songs = [ 'Back In Black' , 'Stairway to Heaven' , 'Hey Jude' ] ;
const Artists = [ 'ACDC' , 'Led Zeppelin' , 'The Beatles' ] ;
function eraseDatabase() { }
function restore_database() { }
2019-02-13 19:15:40 +09:00
type animal = { /* ... */ }
type Container = { /* ... */ }
2019-02-04 09:16:01 +02:00
` ` `
2025-05-01 11:11:48 +02:00
* * Д о б р е : * *
2019-02-04 09:16:01 +02:00
` ` ` ts
const DAYS_IN_WEEK = 7 ;
const DAYS_IN_MONTH = 30 ;
const SONGS = [ 'Back In Black' , 'Stairway to Heaven' , 'Hey Jude' ] ;
const ARTISTS = [ 'ACDC' , 'Led Zeppelin' , 'The Beatles' ] ;
2022-07-15 13:58:56 +02:00
const discography = getArtistDiscography ( 'ACDC' ) ;
const beatlesSongs = SONGS . filter ( ( song ) = > isBeatlesSong ( song ) ) ;
2019-02-04 09:16:01 +02:00
function eraseDatabase() { }
function restoreDatabase() { }
2019-02-13 19:15:40 +09:00
type Animal = { /* ... */ }
type Container = { /* ... */ }
2019-02-04 09:16:01 +02:00
` ` `
2025-05-01 11:11:48 +02:00
П е р е в а г у с л і д в і д д а в а т и в и к о р и с т а н н ю ` PascalCase ` д л я н а з в к л а с і в , і н т е р ф е й с і в , т и п і в т а п р о с т о р і в і м е н .
П е р е в а г у с л і д в і д д а в а т и в и к о р и с т а н н ю ` camelCase ` д л я з м і н н и х , ф у н к ц і й т а ч л е н і в к л а с і в .
П е р е в а г у с л і д в і д д а в а т и в и к о р и с т а н н ю к а п і т а л і з о в а н о г о ` SNAKE_CASE ` д л я к о н с т а н т .
2019-02-04 09:16:01 +02:00
2025-05-01 11:13:28 +02:00
* * [ ⬆ п о в е р н у т и с я д о з м і с т у ] ( # table - of - contents ) * *
2019-02-04 09:16:01 +02:00
2025-05-01 11:11:48 +02:00
# # # Ф у н к ц і ї - в и к л и к а ч і т а ф у н к ц і ї - в и к л и к и п о в и н н і б у т и б л и з ь к и м и
2019-02-04 09:16:01 +02:00
2025-05-01 11:11:48 +02:00
Я к щ о ф у н к ц і я в и к л и к а є і н ш у , т р и м а й т е ц і ф у н к ц і ї в е р т и к а л ь н о б л и з ь к о в в и х і д н о м у ф а й л і . В і д е а л і , т р и м а й т е в и к л и к а ч а п р я м о н а д в и к л и к а н и м .
М и з а з в и ч а й ч и т а є м о к о д з в е р х у в н и з , я к г а з е т у . Ч е р е з ц е , з р о б і т ь в а ш к о д т а к и м , щ о ч и т а є т ь с я т а к и м ч и н о м .
2019-02-04 09:16:01 +02:00
2025-05-01 11:11:48 +02:00
* * П о г а н о : * *
2019-02-04 09:16:01 +02:00
` ` ` ts
class PerformanceReview {
constructor ( private readonly employee : Employee ) {
}
private lookupPeers() {
return db . lookup ( this . employee . id , 'peers' ) ;
}
private lookupManager() {
return db . lookup ( this . employee , 'manager' ) ;
}
private getPeerReviews() {
const peers = this . lookupPeers ( ) ;
// ...
}
review() {
this . getPeerReviews ( ) ;
this . getManagerReview ( ) ;
this . getSelfReview ( ) ;
// ...
}
private getManagerReview() {
const manager = this . lookupManager ( ) ;
}
private getSelfReview() {
// ...
}
}
const review = new PerformanceReview ( employee ) ;
review . review ( ) ;
` ` `
2025-05-01 11:11:48 +02:00
* * Д о б р е : * *
2019-02-04 09:16:01 +02:00
` ` ` ts
class PerformanceReview {
constructor ( private readonly employee : Employee ) {
}
review() {
this . getPeerReviews ( ) ;
this . getManagerReview ( ) ;
this . getSelfReview ( ) ;
// ...
}
private getPeerReviews() {
const peers = this . lookupPeers ( ) ;
// ...
}
private lookupPeers() {
return db . lookup ( this . employee . id , 'peers' ) ;
}
private getManagerReview() {
const manager = this . lookupManager ( ) ;
}
private lookupManager() {
return db . lookup ( this . employee , 'manager' ) ;
2019-02-12 08:40:50 +02:00
}
2019-02-04 09:16:01 +02:00
private getSelfReview() {
// ...
}
}
const review = new PerformanceReview ( employee ) ;
review . review ( ) ;
` ` `
2025-05-01 11:13:28 +02:00
* * [ ⬆ п о в е р н у т и с я д о з м і с т у ] ( # table - of - contents ) * *
2019-02-04 09:16:01 +02:00
2025-05-01 11:11:48 +02:00
# # # О р г а н і з у й т е і м п о р т и
2019-02-11 10:47:27 +02:00
2025-05-01 11:11:48 +02:00
З ч и с т и м и т а л е г к и м и д л я ч и т а н н я о п е р а т о р а м и і м п о р т у в и м о ж е т е ш в и д к о п о б а ч и т и з а л е ж н о с т і п о т о ч н о г о к о д у . П е р е к о н а й т е с я , щ о в и з а с т о с о в у є т е н а с т у п н і х о р о ш і п р а к т и к и д л я о п е р а т о р і в ` import ` :
2019-02-11 10:47:27 +02:00
2025-05-01 11:11:48 +02:00
- О п е р а т о р и і м п о р т у п о в и н н і б у т и в а л ф а в і т н о м у п о р я д к у т а з г р у п о в а н і .
- Н е в и к о р и с т а н і і м п о р т и п о в и н н і б у т и в и д а л е н і .
- І м е н о в а н і і м п о р т и п о в и н н і б у т и в а л ф а в і т н о м у п о р я д к у ( т о б т о ` import {A, B, C} from 'foo'; ` )
- Д ж е р е л а і м п о р т у п о в и н н і б у т и в а л ф а в і т н о м у п о р я д к у в м е ж а х г р у п , т о б т о : ` import * as foo from 'a'; import * as bar from 'b'; `
- П е р е в а г у с л і д в і д д а в а т и в и к о р и с т а н н ю ` import type ` з а м і с т ь ` import ` п р и і м п о р т і л и ш е т и п і в з ф а й л у , щ о б у н и к н у т и ц и к л і в з а л е ж н о с т е й , о с к і л ь к и ц і і м п о р т и с т и р а ю т ь с я п і д ч а с в и к о н а н н я
- Г р у п и і м п о р т у р о з д і л я ю т ь с я п о р о ж н і м и р я д к а м и .
- Г р у п и п о в и н н і п о в а ж а т и н а с т у п н и й п о р я д о к :
- П о л і ф і л и ( т о б т о ` import 'reflect-metadata'; ` )
- В б у д о в а н і м о д у л і Node ( т о б т о ` import fs from 'fs'; ` )
- з о в н і ш н і м о д у л і ( т о б т о ` import { query } from 'itiriri'; ` )
- в н у т р і ш н і м о д у л і ( т о б т о ` import { UserService } from 'src/services/userService'; ` )
- м о д у л і з б а т ь к і в с ь к о г о к а т а л о г у ( т о б т о ` import foo from '../foo'; import qux from '../../foo/qux'; ` )
- м о д у л і з т о г о ж а б о б р а т н ь о г о к а т а л о г у ( т о б т о ` import bar from './bar'; import baz from './bar/baz'; ` )
2019-02-11 10:47:27 +02:00
2025-05-01 11:11:48 +02:00
* * П о г а н о : * *
2019-02-11 10:47:27 +02:00
` ` ` ts
import { TypeDefinition } from '../types/typeDefinition' ;
import { AttributeTypes } from '../model/attribute' ;
2022-07-15 13:58:56 +02:00
import { Customer , Credentials } from '../model/types' ;
2019-02-11 10:47:27 +02:00
import { ApiCredentials , Adapters } from './common/api/authorization' ;
import fs from 'fs' ;
import { ConfigPlugin } from './plugins/config/configPlugin' ;
import { BindingScopeEnum , Container } from 'inversify' ;
import 'reflect-metadata' ;
` ` `
2025-05-01 11:11:48 +02:00
* * Д о б р е : * *
2019-02-11 10:47:27 +02:00
` ` ` ts
import 'reflect-metadata' ;
import fs from 'fs' ;
import { BindingScopeEnum , Container } from 'inversify' ;
import { AttributeTypes } from '../model/attribute' ;
import { TypeDefinition } from '../types/typeDefinition' ;
2022-07-15 13:58:56 +02:00
import type { Customer , Credentials } from '../model/types' ;
2019-02-11 10:47:27 +02:00
import { ApiCredentials , Adapters } from './common/api/authorization' ;
import { ConfigPlugin } from './plugins/config/configPlugin' ;
` ` `
2025-05-01 11:13:28 +02:00
* * [ ⬆ п о в е р н у т и с я д о з м і с т у ] ( # table - of - contents ) * *
2019-02-11 10:47:27 +02:00
2025-05-01 11:11:48 +02:00
# # # В и к о р и с т о в у й т е а л і а с и TypeScript
2019-02-11 10:47:27 +02:00
2025-05-01 11:11:48 +02:00
С т в о р ю й т е б і л ь ш з р у ч н і і м п о р т и , в и з н а ч а ю ч и в л а с т и в о с т і paths т а baseUrl у р о з д і л і compilerOptions у ф а й л і ` tsconfig.json `
2019-02-11 10:47:27 +02:00
2025-05-01 11:11:48 +02:00
Ц е д о з в о л и т ь у н и к н у т и д о в г и х в і д н о с н и х ш л я х і в п р и і м п о р т і .
2019-02-11 10:47:27 +02:00
2025-05-01 11:11:48 +02:00
* * П о г а н о : * *
2019-02-11 10:47:27 +02:00
` ` ` ts
import { UserService } from '../../../services/UserService' ;
` ` `
2025-05-01 11:11:48 +02:00
* * Д о б р е : * *
2019-02-11 10:47:27 +02:00
` ` ` ts
import { UserService } from '@services/UserService' ;
` ` `
` ` ` js
// tsconfig.json
. . .
"compilerOptions" : {
. . .
"baseUrl" : "src" ,
"paths" : {
"@services" : [ "services/*" ]
}
. . .
}
. . .
` ` `
2025-05-01 11:13:28 +02:00
* * [ ⬆ п о в е р н у т и с я д о з м і с т у ] ( # table - of - contents ) * *
2019-02-11 10:47:27 +02:00
2025-05-01 11:11:48 +02:00
# # К о м е н т а р і
2019-01-28 17:56:21 +02:00
2025-05-01 11:11:48 +02:00
В и к о р и с т а н н я к о м е н т а р і в є о з н а к о ю н е с п р о м о ж н о с т і в и с л о в и т и с я б е з н и х . К о д п о в и н е н б у т и є д и н и м д ж е р е л о м п р а в д и .
2019-01-28 17:56:21 +02:00
2025-05-01 11:11:48 +02:00
> Н е к о м е н т у й т е п о г а н и й к о д — п е р е п и ш і т ь й о г о .
2019-01-28 17:56:21 +02:00
> — * Brian W . Kernighan and P . J . Plaugher *
2025-05-01 11:11:48 +02:00
# # # В і д д а в а й т е п е р е в а г у с а м о п о я с н ю ю ч о м у к о д у з а м і с т ь к о м е н т а р і в
2019-01-28 17:56:21 +02:00
2025-05-01 11:11:48 +02:00
К о м е н т а р і — ц е в и б а ч е н н я , а н е в и м о г а . Х о р о ш и й к о д * з д е б і л ь ш о г о * д о к у м е н т у є с а м с е б е .
2019-01-28 17:56:21 +02:00
2025-05-01 11:11:48 +02:00
* * П о г а н о : * *
2019-01-28 17:56:21 +02:00
` ` ` ts
2025-05-01 11:11:48 +02:00
// Перевірити, чи підписка активна.
2019-01-28 17:58:45 +02:00
if ( subscription . endDate > Date . now ) { }
2019-01-28 17:56:21 +02:00
` ` `
2025-05-01 11:11:48 +02:00
* * Д о б р е : * *
2019-01-28 17:56:21 +02:00
` ` ` ts
2019-01-28 17:58:45 +02:00
const isSubscriptionActive = subscription . endDate > Date . now ;
2019-01-28 17:56:21 +02:00
if ( isSubscriptionActive ) { /* ... */ }
` ` `
2025-05-01 11:13:28 +02:00
* * [ ⬆ п о в е р н у т и с я д о з м і с т у ] ( # table - of - contents ) * *
2019-01-28 17:56:21 +02:00
2025-05-01 11:11:48 +02:00
# # # Н е з а л и ш а й т е з а к о м е н т о в а н и й к о д у с в о ї й к о д о в і й б а з і
2019-01-28 17:56:21 +02:00
2025-05-01 11:11:48 +02:00
К о н т р о л ь в е р с і й і с н у є н е п р о с т о т а к . З а л и ш т е с т а р и й к о д у в а ш і й і с т о р і ї .
2019-01-28 17:56:21 +02:00
2025-05-01 11:11:48 +02:00
* * П о г а н о : * *
2019-01-28 17:56:21 +02:00
` ` ` ts
2019-02-07 21:53:16 +02:00
type User = {
2019-01-28 17:56:21 +02:00
name : string ;
email : string ;
// age: number;
// jobPosition: string;
}
` ` `
2025-05-01 11:11:48 +02:00
* * Д о б р е : * *
2019-01-28 17:56:21 +02:00
` ` ` ts
2019-02-07 21:53:16 +02:00
type User = {
2019-01-28 17:56:21 +02:00
name : string ;
email : string ;
}
` ` `
2025-05-01 11:13:28 +02:00
* * [ ⬆ п о в е р н у т и с я д о з м і с т у ] ( # table - of - contents ) * *
2019-02-04 18:18:27 +02:00
2025-05-01 11:11:48 +02:00
# # # Н е в е д і т ь ж у р н а л у к о м е н т а р я х
2019-01-28 17:56:21 +02:00
2025-05-01 11:11:48 +02:00
П а м ' я т а й т е , в и к о р и с т о в у й т е к о н т р о л ь в е р с і й ! Н е м а є п о т р е б и в м е р т в о м у к о д і , з а к о м е н т о в а н о м у к о д і , і о с о б л и в о в к о м е н т а р я х - ж у р н а л а х . В и к о р и с т о в у й т е ` git log ` , щ о б о т р и м а т и і с т о р і ю !
2019-01-28 17:56:21 +02:00
2025-05-01 11:11:48 +02:00
* * П о г а н о : * *
2019-01-28 17:56:21 +02:00
` ` ` ts
/ * *
2025-05-01 11:11:48 +02:00
* 2016 - 12 - 20 : Видалені м о н а д и , н е з р о з у м і в ї х ( RM )
* 2016 - 10 - 01 : Покращено в и к о р и с т а н н я с п е ц і а л ь н и х м о н а д ( JP )
* 2016 - 02 - 03 : Додано п е р е в і р к у т и п і в ( LI )
* 2015 - 03 - 14 : Реалізовано combine ( JR )
2019-01-28 17:56:21 +02:00
* /
2019-02-06 10:43:37 +02:00
function combine ( a : number , b : number ) : number {
2019-01-28 17:56:21 +02:00
return a + b ;
}
` ` `
2025-05-01 11:11:48 +02:00
* * Д о б р е : * *
2019-01-28 17:56:21 +02:00
` ` ` ts
2019-02-06 10:43:37 +02:00
function combine ( a : number , b : number ) : number {
2019-01-28 17:56:21 +02:00
return a + b ;
}
` ` `
2025-05-01 11:13:28 +02:00
* * [ ⬆ п о в е р н у т и с я д о з м і с т у ] ( # table - of - contents ) * *
2019-01-28 17:56:21 +02:00
2025-05-01 11:11:48 +02:00
# # # У н и к а й т е п о з и ц і й н и х м а р к е р і в
2019-01-28 17:56:21 +02:00
2025-05-01 11:11:48 +02:00
В о н и з а з в и ч а й л и ш е д о д а ю т ь ш у м у . Н е х а й н а з в и ф у н к ц і й т а з м і н н и х р а з о м з п р а в и л ь н и м в і д с т у п о м т а ф о р м а т у в а н н я м н а д а ю т ь в а ш о м у к о д у в і з у а л ь н у с т р у к т у р у .
Б і л ь ш і с т ь с е р е д о в и щ р о з р о б к и п і д т р и м у ю т ь ф у н к ц і ю з г о р т а н н я к о д у , щ о д о з в о л я є з г о р т а т и / р о з г о р т а т и б л о к и к о д у ( д и в . [ з г о р т а н н я р е г і о н і в ] ( https : //code.visualstudio.com/updates/v1_17#_folding-regions) у Visual Studio Code).
2019-01-28 17:56:21 +02:00
2025-05-01 11:11:48 +02:00
* * П о г а н о : * *
2019-01-28 17:56:21 +02:00
` ` ` ts
////////////////////////////////////////////////////////////////////////////////
2025-05-01 11:11:48 +02:00
// Клас клієнта
2019-01-28 17:56:21 +02:00
////////////////////////////////////////////////////////////////////////////////
class Client {
id : number ;
name : string ;
address : Address ;
contact : Contact ;
////////////////////////////////////////////////////////////////////////////////
2025-05-01 11:11:48 +02:00
// публічні методи
2019-01-28 17:56:21 +02:00
////////////////////////////////////////////////////////////////////////////////
public describe ( ) : string {
// ...
}
////////////////////////////////////////////////////////////////////////////////
2025-05-01 11:11:48 +02:00
// приватні методи
2019-01-28 17:56:21 +02:00
////////////////////////////////////////////////////////////////////////////////
private describeAddress ( ) : string {
// ...
}
private describeContact ( ) : string {
// ...
}
} ;
` ` `
2025-05-01 11:11:48 +02:00
* * Д о б р е : * *
2019-01-28 17:56:21 +02:00
` ` ` ts
class Client {
id : number ;
name : string ;
address : Address ;
contact : Contact ;
public describe ( ) : string {
// ...
}
private describeAddress ( ) : string {
// ...
}
private describeContact ( ) : string {
// ...
}
} ;
` ` `
2025-05-01 11:13:28 +02:00
* * [ ⬆ п о в е р н у т и с я д о з м і с т у ] ( # table - of - contents ) * *
2019-02-09 22:31:00 +02:00
2025-05-01 11:11:48 +02:00
# # # К о м е н т а р і TODO
2019-02-09 22:31:00 +02:00
2025-05-01 11:11:48 +02:00
К о л и в и р о з у м і є т е , щ о в а м п о т р і б н о з а л и ш и т и н о т а т к и в к о д і д л я п і з н і ш и х в д о с к о н а л е н ь ,
р о б і т ь ц е з а д о п о м о г о ю к о м е н т а р і в ` // TODO ` . Б і л ь ш і с т ь IDE м а ю т ь с п е ц і а л ь н у п і д т р и м к у т а к и х к о м е н т а р і в , т о м у
в и м о ж е т е ш в и д к о п е р е г л я н у т и в е с ь с п и с о к todos .
2019-02-09 22:31:00 +02:00
2025-05-01 11:11:48 +02:00
О д н а к м а й т е н а у в а з і , щ о к о м е н т а р * TODO * н е є в и п р а в д а н н я м д л я п о г а н о г о к о д у .
2019-02-09 22:31:00 +02:00
2025-05-01 11:11:48 +02:00
* * П о г а н о : * *
2019-02-09 22:31:00 +02:00
` ` ` ts
function getActiveSubscriptions ( ) : Promise < Subscription [ ] > {
2025-05-01 11:11:48 +02:00
// переконатися, що `dueDate` проіндексовано.
2019-02-09 22:31:00 +02:00
return db . subscriptions . find ( { dueDate : { $lte : new Date ( ) } } ) ;
}
` ` `
2025-05-01 11:11:48 +02:00
* * Д о б р е : * *
2019-02-09 22:31:00 +02:00
` ` ` ts
function getActiveSubscriptions ( ) : Promise < Subscription [ ] > {
2025-05-01 11:11:48 +02:00
// TODO: переконатися, що `dueDate` проіндексовано.
2019-02-09 22:31:00 +02:00
return db . subscriptions . find ( { dueDate : { $lte : new Date ( ) } } ) ;
}
` ` `
2025-05-01 11:13:28 +02:00
* * [ ⬆ п о в е р н у т и с я д о з м і с т у ] ( # table - of - contents ) * *
2019-02-12 08:48:13 +02:00
2025-05-01 11:11:48 +02:00
# # П е р е к л а д и
2019-02-12 08:48:13 +02:00
2025-05-01 11:11:48 +02:00
Ц е т а к о ж д о с т у п н о і н ш и м и м о в а м и :
- ! [ br ] ( https : //raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Brazil.png) **Бразильська португальська**: [vitorfreitas/clean-code-typescript](https://github.com/vitorfreitas/clean-code-typescript)
- ! [ cn ] ( https : //raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/China.png) **Китайська**:
2019-02-18 10:16:55 +02:00
- [ beginor / clean - code - typescript ] ( https : //github.com/beginor/clean-code-typescript)
- [ pipiliang / clean - code - typescript ] ( https : //github.com/pipiliang/clean-code-typescript)
2025-05-01 11:11:48 +02:00
- ! [ fr ] ( https : //raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/France.png) **Французька**: [ralflorent/clean-code-typescript](https://github.com/ralflorent/clean-code-typescript)
- ! [ de ] ( https : //raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Germany.png) **Німецька**: [mheob/clean-code-typescript](https://github.com/mheob/clean-code-typescript)
- ! [ ja ] ( https : //raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Japan.png) **Японська**: [MSakamaki/clean-code-typescript](https://github.com/MSakamaki/clean-code-typescript)
- ! [ ko ] ( https : //raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/South-Korea.png) **Корейська**: [738/clean-code-typescript](https://github.com/738/clean-code-typescript)
- ! [ ru ] ( https : //raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Russia.png) **Російська**: [Real001/clean-code-typescript](https://github.com/Real001/clean-code-typescript)
- ! [ es ] ( https : //raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Spain.png) **Іспанська**: [3xp1o1t/clean-code-typescript](https://github.com/3xp1o1t/clean-code-typescript)
- ! [ tr ] ( https : //raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Turkey.png) **Турецька**: [ozanhonamlioglu/clean-code-typescript](https://github.com/ozanhonamlioglu/clean-code-typescript)
- ! [ vi ] ( https : //raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Vietnam.png) **В 'єтнамська**: [hoangsetup/clean-code-typescript](https://github.com/hoangsetup/clean-code-typescript)
П о с и л а н н я б у д у т ь д о д а н і п і с л я з а в е р ш е н н я п е р е к л а д і в .
П е р е в і р т е ц ю [ д и с к у с і ю ] ( https : //github.com/labs42io/clean-code-typescript/issues/15) для отримання додаткових деталей та прогресу.
В и м о ж е т е з р о б и т и н е о ц і н е н н и й в н е с о к у с п і л ь н о т у * Clean Code * , п е р е к л а в ш и ц е в а ш о ю м о в о ю .
2025-05-01 11:13:28 +02:00
* * [ ⬆ п о в е р н у т и с я д о з м і с т у ] ( # table - of - contents ) * *