paint-brush
TypeScript'in Gücünü Ortaya Çıkarma: tsconfig'te Önemli Hususlarile@nodge
2,702 okumalar
2,702 okumalar

TypeScript'in Gücünü Ortaya Çıkarma: tsconfig'te Önemli Hususlar

ile Maksim Zemskov13m2023/07/12
Read on Terminal Reader
Read this story w/o Javascript

Çok uzun; Okumak

TypeScript, güçlü tip sistemi ve statik analiz yetenekleri sayesinde karmaşık uygulamalar oluşturmak için popüler bir dildir. Ancak maksimum tür güvenliğine ulaşmak için tsconfig'in doğru şekilde yapılandırılması önemlidir. Bu makalede, optimum tür güvenliğini elde etmek için tsconfig'i yapılandırmaya yönelik temel hususları tartışacağız.
featured image - TypeScript'in Gücünü Ortaya Çıkarma: tsconfig'te Önemli Hususlar
Maksim Zemskov HackerNoon profile picture
0-item
1-item

Karmaşık web uygulamaları oluşturuyorsanız TypeScript muhtemelen programlama diliniz olacaktır. TypeScript, güçlü tür sistemi ve statik analiz yetenekleri nedeniyle çok sevilir ve bu da onu kodunuzun sağlam ve hatasız olmasını sağlamak için güçlü bir araç haline getirir.


Ayrıca kod düzenleyicilerle entegrasyon yoluyla geliştirme sürecini hızlandırarak geliştiricilerin kodda daha verimli bir şekilde gezinmesine, daha doğru ipuçları ve otomatik tamamlama almasına olanak tanır ve büyük miktarlarda kodun güvenli bir şekilde yeniden düzenlenmesine olanak tanır.


Derleyici, TypeScript'in kalbidir ve tür doğruluğunu kontrol etmekten ve TypeScript kodunu JavaScript'e dönüştürmekten sorumludur. Ancak TypeScript'in gücünden tam olarak yararlanmak için Derleyiciyi doğru şekilde yapılandırmak önemlidir.


Her TypeScript projesinde Derleyicinin tüm yapılandırma seçeneklerini içeren bir veya daha fazla tsconfig.json dosyası bulunur.


Tsconfig'i yapılandırmak, TypeScript projelerinizde optimum tür güvenliği ve geliştirici deneyimi elde etmek için çok önemli bir adımdır. İlgili tüm önemli faktörleri dikkatle değerlendirmek için zaman ayırarak geliştirme sürecini hızlandırabilir ve kodunuzun sağlam ve hatasız olduğundan emin olabilirsiniz.

Standart Yapılandırmanın Dezavantajları

Tsconfig'teki varsayılan yapılandırma, geliştiricilerin TypeScript'in avantajlarının çoğunu kaçırmasına neden olabilir. Bunun nedeni, pek çok güçlü tür denetimi özelliğini etkinleştirmemesidir. "Varsayılan" yapılandırmayla, hiçbir tür denetimi derleyici seçeneğinin ayarlanmadığı bir yapılandırmayı kastediyorum.


Örneğin:


 { "compilerOptions": { "target": "esnext", "module": "esnext", "esModuleInterop": true, "forceConsistentCasingInFileNames": true, "skipLibCheck": true, }, "include": ["src"] }


Birkaç temel yapılandırma seçeneğinin bulunmaması, iki temel nedenden dolayı kod kalitesinin düşmesine neden olabilir. İlk olarak, TypeScript'in derleyicisi çeşitli durumlarda null ve undefined türleri hatalı şekilde işleyebilir.


İkinci olarak, any tür kod tabanınızda kontrolsüz bir şekilde görünebilir ve bu da bu türün devre dışı bırakılmasına yol açabilir.


Neyse ki, yapılandırmadaki birkaç seçeneği değiştirerek bu sorunları düzeltmek kolaydır.

Katı Mod

 { "compilerOptions": { "strict": true } }


Katı mod, çok çeşitli tür denetimi davranışlarını etkinleştirerek programın doğruluğu konusunda daha güçlü garantiler sağlayan önemli bir yapılandırma seçeneğidir.


Tsconfig dosyasında katı modun etkinleştirilmesi, maksimum tür güvenliğine ve daha iyi bir geliştirici deneyimine ulaşma yolunda önemli bir adımdır.


Tsconfig'i yapılandırmak biraz daha fazla çaba gerektirir, ancak projenizin kalitesini artırmada uzun bir yol kat edebilir.


strict derleyici seçeneği, diğerlerinin yanı sıra noImplicitAny , strictNullChecks , strictFunctionTypes dahil tüm katı mod ailesi seçeneklerini etkinleştirir.


Bu seçenekler ayrı ayrı da yapılandırılabilir ancak hiçbirinin kapatılması önerilmez. Nedenini görmek için örneklere bakalım.

Örtülü Herhangi Bir Çıkarım

 { "compilerOptions": { "noImplicitAny": true } }


any tür, statik tür sisteminde tehlikeli bir boşluktur ve bunun kullanılması tüm tür denetimi kurallarını devre dışı bırakır. Sonuç olarak TypeScript'in tüm avantajları kaybolur: hatalar gözden kaçırılır, kod düzenleyici ipuçları düzgün çalışmayı durdurur vb.


any kullanılması yalnızca aşırı durumlarda veya prototip oluşturma ihtiyaçları için uygundur. En iyi çabalarımıza rağmen, any tür bazen dolaylı olarak kod tabanına gizlice girebilir.


Varsayılan olarak derleyici, any hatanın kod tabanında görünmesi karşılığında bizi birçok hatayı affeder. Spesifik olarak TypeScript, tür otomatik olarak çıkarılamasa bile değişkenlerin türünü belirtmememize olanak tanır.


Sorun, yanlışlıkla bir değişkenin türünü (örneğin bir işlev argümanına) belirtmeyi unutabilmemizdir. TypeScript, bir hata göstermek yerine değişkenin türünü otomatik olarak any şekilde çıkaracaktır.


 function parse(str) { // ^? any return str.split(''); } // TypeError: str.split is not a function const res1 = parse(42); const res2 = parse('hello'); // ^? any


noImplicitAny derleyici seçeneğinin etkinleştirilmesi, derleyicinin değişken türünün otomatik olarak any olarak çıkarıldığı tüm yerleri vurgulamasına neden olur. Örneğimizde TypeScript bizden fonksiyon argümanının tipini belirtmemizi isteyecektir.


 function parse(str) { // ^ Error: Parameter 'str' implicitly has an 'any' type. return str.split(''); }


Türü belirttiğimizde TypeScript, bir sayıyı string parametresine geçirme hatasını hızlı bir şekilde yakalayacaktır. res2 değişkeninde saklanan fonksiyonun dönüş değeri de doğru türde olacaktır.


 function parse(str: string) { return str.split(''); } const res1 = parse(42); // ^ Error: Argument of type 'number' is not // assignable to parameter of type 'string' const res2 = parse('hello'); // ^? string[]


Yakalama Değişkenlerinde Bilinmeyen Tür

 { "compilerOptions": { "useUnknownInCatchVariables": true } }


useUnknownInCatchVariables yapılandırılması, try-catch bloklarındaki istisnaların güvenli bir şekilde işlenmesine olanak tanır. Varsayılan olarak TypeScript, catch bloğundaki hata türünün any olduğunu varsayar ve bu da hatayla ilgili her şeyi yapmamıza olanak tanır.


Örneğin, yakalanan hatayı olduğu gibi Error örneğini kabul eden bir günlük kaydı işlevine iletebiliriz.


 function logError(err: Error) { // ... } try { return JSON.parse(userInput); } catch (err) { // ^? any logError(err); }


Ancak gerçekte hatanın türü hakkında hiçbir garanti yoktur ve gerçek türünü yalnızca hata oluştuğunda çalışma zamanında belirleyebiliriz. Günlük işlevi Error olmayan bir şey alırsa, bu bir çalışma zamanı hatasıyla sonuçlanacaktır.


Bu nedenle, useUnknownInCatchVariables seçeneği, hatayla ilgili any bir şey yapmadan önce hatanın türünü kontrol etmemizi bize hatırlatmak için hatanın türünü herhangi bir durumdan unknown değiştirir.


 try { return JSON.parse(userInput); } catch (err) { // ^? unknown // Now we need to check the type of the value if (err instanceof Error) { logError(err); } else { logError(new Error('Unknown Error')); } }


Artık TypeScript, logError işlevine aktarmadan önce err değişkeninin türünü kontrol etmemizi isteyecek, böylece daha doğru ve daha güvenli kod elde edeceğiz. Ne yazık ki bu seçenek, promise.catch() işlevlerinde veya geri çağırma işlevlerindeki yazım hatalarında yardımcı olmaz.


Ancak bir sonraki makalede bu gibi any başa çıkmanın yollarını tartışacağız.

Çağrı ve Uygulama Yöntemlerini Kontrol Etme

 { "compilerOptions": { "strictBindCallApply": true } }


Başka bir seçenek, any işlev içi çağrının görünümünü call ve apply yoluyla düzeltir. Bu, ilk ikisine göre daha az görülen bir durumdur ancak yine de dikkate alınması önemlidir. Varsayılan olarak TypeScript bu tür yapılardaki türleri hiçbir şekilde denetlemez.


Örneğin, herhangi bir şeyi bir fonksiyona argüman olarak iletebiliriz ve sonunda her zaman any tipini alırız.


 function parse(value: string) { return parseInt(value, 10); } const n1 = parse.call(undefined, '10'); // ^? any const n2 = parse.call(undefined, false); // ^? any


strictBindCallApply seçeneğinin etkinleştirilmesi TypeScript'i daha akıllı hale getirir, böylece dönüş türü doğru bir şekilde number olarak anlaşılır. Ve yanlış türde bir argüman iletilmeye çalışıldığında TypeScript hatayı gösterecektir.


 function parse(value: string) { return parseInt(value, 10); } const n1 = parse.call(undefined, '10'); // ^? number const n2 = parse.call(undefined, false); // ^ Argument of type 'boolean' is not // assignable to parameter of type 'string'.


Yürütme Bağlamı için Katı Türler

 { "compilerOptions": { "noImplicitThis": true } }


Projenizde any görünmesini engellemeye yardımcı olabilecek bir sonraki seçenek, işlev çağrılarında yürütme bağlamının işlenmesini düzeltir. JavaScript'in dinamik doğası, bir işlevin içindeki bağlamın türünü statik olarak belirlemeyi zorlaştırır.


TypeScript, varsayılan olarak bu gibi durumlarda bağlam için any türünü kullanır ve herhangi bir uyarı sağlamaz.


 class Person { private name: string; constructor(name: string) { this.name = name; } getName() { return function () { return this.name; // ^ 'this' implicitly has type 'any' because // it does not have a type annotation. }; } }


noImplicitThis derleyici seçeneğinin etkinleştirilmesi, bir işlevin bağlam türünü açıkça belirtmemizi isteyecektir. Böylece yukarıdaki örnekte Person sınıfının name alanı yerine fonksiyon içeriğine erişme hatasını yakalayabiliriz.


TypeScript'te Boş ve Tanımsız Destek

 { "compilerOptions": { "strictNullChecks": true } }


strict modda yer alan sonraki birkaç seçenek, kod tabanında any türün görünmesine neden olmaz. Ancak TS derleyicisinin davranışını daha katı hale getirirler ve geliştirme sırasında daha fazla hatanın bulunmasına izin verirler.


Bu tür ilk seçenek TypeScript'te null ve undefined işlenmesini düzeltir. TypeScript, varsayılan olarak null ve undefined değerlerin herhangi bir tür için geçerli değerler olduğunu varsayar; bu da beklenmeyen çalışma zamanı hatalarına neden olabilir.


strictNullChecks derleyici seçeneğinin etkinleştirilmesi, geliştiriciyi null ve undefined durumların oluşabileceği durumları açıkça ele almaya zorlar.


Örneğin aşağıdaki kodu göz önünde bulundurun:


 const users = [ { name: 'Oby', age: 12 }, { name: 'Heera', age: 32 }, ]; const loggedInUser = users.find(u => u.name === 'Max'); // ^? { name: string; age: number; } console.log(loggedInUser.age); // ^ TypeError: Cannot read properties of undefined


Bu kod hatasız derlenecektir ancak sistemde “Max” isimli kullanıcı mevcut değilse ve users.find() fonksiyonu undefined döndürüyorsa çalışma zamanı hatası verebilir. Bunu önlemek için strictNullChecks derleyici seçeneğini etkinleştirebiliriz.


Artık TypeScript bizi, users.find() tarafından döndürülen null veya undefined olasılığını açıkça ele almaya zorlayacak.


 const loggedInUser = users.find(u => u.name === 'Max'); // ^? { name: string; age: number; } | undefined if (loggedInUser) { console.log(loggedInUser.age); }


null ve undefiined olasılığını açıkça ele alarak çalışma zamanı hatalarını önleyebilir ve kodumuzun daha sağlam ve hatasız olmasını sağlayabiliriz.

Katı İşlev Türleri

 { "compilerOptions": { "strictFunctionTypes": true } }


strictFunctionTypes etkinleştirilmesi TypeScript'in derleyicisini daha akıllı hale getirir. Sürüm 2.6'dan önce TypeScript, işlev bağımsız değişkenlerinin çelişkisini kontrol etmiyordu. İşlev yanlış türde bir bağımsız değişkenle çağrılırsa bu, çalışma zamanı hatalarına yol açacaktır.


Örneğin, bir fonksiyon türü hem dizeleri hem de sayıları işleyebiliyor olsa bile, bu türe yalnızca dizeleri işleyebilen bir işlev atayabiliriz. Bu fonksiyona hala bir sayı iletebiliriz ancak çalışma zamanı hatası alırız.


 function greet(x: string) { console.log("Hello, " + x.toLowerCase()); } type StringOrNumberFn = (y: string | number) => void; // Incorrect Assignment const func: StringOrNumberFn = greet; // TypeError: x.toLowerCase is not a function func(10);


Neyse ki, strictFunctionTypes seçeneğinin etkinleştirilmesi bu davranışı düzeltir ve derleyici bu hataları derleme zamanında yakalayabilir ve bize işlevlerdeki tür uyumsuzluğuna ilişkin ayrıntılı bir mesaj gösterebilir.


 const func: StringOrNumberFn = greet; // ^ Type '(x: string) => void' is not assignable to type 'StringOrNumberFn'. // Types of parameters 'x' and 'y' are incompatible. // Type 'string | number' is not assignable to type 'string'. // Type 'number' is not assignable to type 'string'.


Sınıf Özelliğini Başlatma

 { "compilerOptions": { "strictPropertyInitialization": true } }


Son olarak, strictPropertyInitialization seçeneği, değer olarak undefined içermeyen türler için zorunlu sınıf özelliği başlatma işleminin kontrol edilmesini sağlar.


Örneğin, aşağıdaki kodda geliştirici email özelliğini başlatmayı unuttu. Varsayılan olarak TypeScript bu hatayı algılamaz ve çalışma zamanında bir sorun ortaya çıkabilir.


 class UserAccount { name: string; email: string; constructor(name: string) { this.name = name; // Forgot to assign a value to this.email } }


Ancak strictPropertyInitialization seçeneği etkinleştirildiğinde TypeScript bu sorunu bizim için vurgulayacaktır.


 email: string; // ^ Error: Property 'email' has no initializer and // is not definitely assigned in the constructor.

Güvenli Dizin İmzaları

 { "compilerOptions": { "noUncheckedIndexedAccess": true } }


noUncheckedIndexedAccess seçeneği strict modun bir parçası değildir ancak projenizdeki kod kalitesini artırmanıza yardımcı olabilecek başka bir seçenektir. Dizin erişim ifadelerinin null veya undefined bir dönüş türüne sahip olup olmadığının kontrol edilmesini sağlar, bu da çalışma zamanı hatalarını önleyebilir.


Önbelleğe alınmış değerleri depolamak için bir nesnemizin olduğu aşağıdaki örneği düşünün. Daha sonra anahtarlardan birinin değerini alıyoruz. Elbette istenilen anahtara ait değerin gerçekten önbellekte mevcut olduğuna dair bir garantimiz yoktur.


Varsayılan olarak TypeScript, değerin var olduğunu ve string türüne sahip olduğunu varsayar. Bu çalışma zamanı hatasına yol açabilir.


 const cache: Record<string, string> = {}; const value = cache['key']; // ^? string console.log(value.toUpperCase()); // ^ TypeError: Cannot read properties of undefined


TypeScript'te noUncheckedIndexedAccess seçeneğinin etkinleştirilmesi, undefined dönüş türü için dizin erişim ifadelerinin kontrol edilmesini gerektirir; bu, çalışma zamanı hatalarından kaçınmamıza yardımcı olabilir. Bu aynı zamanda bir dizideki öğelere erişim için de geçerlidir.


 const cache: Record<string, string> = {}; const value = cache['key']; // ^? string | undefined if (value) { console.log(value.toUpperCase()); }

Önerilen Yapılandırma

Tartışılan seçeneklere bağlı olarak, optimum tür güvenliği için projenizin tsconfig.json dosyasında strict ve noUncheckedIndexedAccess seçeneklerinin etkinleştirilmesi önemle tavsiye edilir.


 { "compilerOptions": { "strict": true, "noUncheckedIndexedAccess": true, } }


strict seçeneğini zaten etkinleştirdiyseniz, strict: true seçeneğinin kopyalanmasını önlemek için aşağıdaki seçenekleri kaldırmayı düşünebilirsiniz:


  • noImplicitAny
  • useUnknownInCatchVariables
  • strictBindCallApply
  • noImplicitThis
  • strictFunctionTypes
  • strictNullChecks
  • strictPropertyInitialization


Ayrıca tür sistemini zayıflatabilecek veya çalışma zamanı hatalarına neden olabilecek aşağıdaki seçeneklerin de kaldırılması önerilir:


  • keyofStringsOnly
  • noStrictGenericChecks
  • suppressImplicitAnyIndexErrors
  • suppressExcessPropertyErrors


Bu seçenekleri dikkatlice değerlendirip yapılandırarak TypeScript projelerinizde optimum tür güvenliğine ve daha iyi bir geliştirici deneyimine ulaşabilirsiniz.

Çözüm

TypeScript, derleyicisini ve yazım sistemini sürekli geliştirerek evriminde uzun bir yol kat etti. Ancak geriye dönük uyumluluğu sürdürmek için TypeScript yapılandırması, tür denetiminin kalitesini önemli ölçüde etkileyebilecek birçok seçenekle birlikte daha karmaşık hale geldi.


Bu seçenekleri dikkatlice değerlendirip yapılandırarak TypeScript projelerinizde optimum tür güvenliğine ve daha iyi bir geliştirici deneyimine ulaşabilirsiniz. Bir proje yapılandırmasında hangi seçeneklerin etkinleştirileceğini ve hangi seçeneklerin kaldırılacağını bilmek önemlidir.


Belirli seçenekleri devre dışı bırakmanın sonuçlarını anlamak, her biri için bilinçli kararlar vermenizi sağlayacaktır.


Kesin yazımın sonuçları olabileceğini akılda tutmak önemlidir. JavaScript'in dinamik doğasını etkili bir şekilde ele almak için, bir değişkenden sonra yalnızca "sayı" veya "dize" belirtmenin ötesinde TypeScript'i iyi anlamanız gerekir.


Ortaya çıkacak türle ilgili sorunları daha etkili bir şekilde çözmek için daha karmaşık yapılara ve TypeScript'in ilk kitaplık ve araç ekosistemine aşina olmanız gerekecektir.


Sonuç olarak kod yazmak biraz daha fazla çaba gerektirebilir ancak tecrübelerime dayanarak uzun vadeli projeler için bu çabaya değdiğini düşünüyorum.


Umarım bu makaleden yeni bir şeyler öğrenmişsinizdir. Bu bir serinin ilk bölümü. Bir sonraki makalede TypeScript'in standart kitaplığındaki türleri iyileştirerek daha iyi tür güvenliği ve kod kalitesine nasıl ulaşabileceğimizi tartışacağız. Bizi izlemeye devam edin ve okuduğunuz için teşekkürler!

kullanışlı bağlantılar