복잡한 웹 애플리케이션을 구축하는 경우 TypeScript가 프로그래밍 언어로 선택될 가능성이 높습니다. TypeScript는 강력한 유형 시스템과 정적 분석 기능으로 많은 사랑을 받고 있으며, 코드가 강력하고 오류가 없는지 확인하는 강력한 도구입니다. 또한 코드 편집기와의 통합을 통해 개발 프로세스를 가속화하여 개발자가 코드를 보다 효율적으로 탐색하고 보다 정확한 힌트와 자동 완성을 얻을 수 있을 뿐만 아니라 대량의 코드를 안전하게 리팩토링할 수 있습니다. 컴파일러는 유형 정확성을 확인하고 TypeScript 코드를 JavaScript로 변환하는 역할을 하는 TypeScript의 핵심입니다. 그러나 TypeScript의 기능을 최대한 활용하려면 컴파일러를 올바르게 구성하는 것이 중요합니다. 각 TypeScript 프로젝트에는 컴파일러에 대한 모든 구성 옵션을 보유하는 하나 이상의 파일이 있습니다. tsconfig.json tsconfig 구성은 TypeScript 프로젝트에서 최적의 유형 안전성과 개발자 경험을 달성하는 데 중요한 단계입니다. 관련된 모든 핵심 요소를 신중하게 고려하는 데 시간을 투자하면 개발 프로세스 속도를 높이고 코드가 강력하고 오류가 없는지 확인할 수 있습니다. 표준 구성의 단점 tsconfig의 기본 구성으로 인해 개발자는 TypeScript의 대부분의 이점을 놓칠 수 있습니다. 이는 많은 강력한 유형 검사 기능을 활성화하지 않기 때문입니다. "기본" 구성이란 유형 검사 컴파일러 옵션이 설정되지 않은 구성을 의미합니다. 예를 들어: { "compilerOptions": { "target": "esnext", "module": "esnext", "esModuleInterop": true, "forceConsistentCasingInFileNames": true, "skipLibCheck": true, }, "include": ["src"] } 몇 가지 주요 구성 옵션이 없으면 두 가지 주요 이유로 인해 코드 품질이 저하될 수 있습니다. 첫째, TypeScript의 컴파일러는 다양한 경우에 및 유형을 잘못 처리할 수 있습니다. null undefined 둘째, 유형이 코드베이스에 제어할 수 없게 나타날 수 있으며, 이로 인해 이 유형에 대한 유형 검사가 비활성화될 수 있습니다. any 다행히도 이러한 문제는 구성에서 몇 가지 옵션을 조정하면 쉽게 해결할 수 있습니다. 엄격 모드 { "compilerOptions": { "strict": true } } 엄격 모드는 광범위한 유형 검사 동작을 활성화하여 프로그램 정확성을 더욱 강력하게 보장하는 필수 구성 옵션입니다. tsconfig 파일에서 엄격 모드를 활성화하는 것은 최대 유형 안전성과 더 나은 개발자 경험을 달성하기 위한 중요한 단계입니다. tsconfig를 구성하는 데 약간의 추가 노력이 필요하지만 프로젝트 품질을 향상시키는 데 큰 도움이 될 수 있습니다. 컴파일러 옵션은 , , 등을 포함한 모든 엄격 모드 제품군 옵션을 활성화합니다. strict noImplicitAny strictNullChecks strictFunctionTypes 이러한 옵션은 별도로 구성할 수도 있지만 해당 옵션을 끄는 것은 권장되지 않습니다. 그 이유를 알아보기 위해 예를 살펴보겠습니다. 암시적 추론 { "compilerOptions": { "noImplicitAny": true } } 유형은 정적 유형 시스템의 위험한 허점이며 이를 사용하면 모든 유형 검사 규칙이 비활성화됩니다. 결과적으로 TypeScript의 모든 이점이 사라집니다. 버그가 누락되고, 코드 편집기 힌트가 제대로 작동하지 않는 등의 문제가 발생합니다. any 극단적인 경우나 프로토타입 제작이 필요한 경우 것을 사용해도 괜찮습니다. 최선의 노력에도 불구하고 유형이 때때로 암시적으로 코드베이스에 몰래 들어갈 수 있습니다. any any 기본적으로 컴파일러는 코드베이스에 나타나는 대가로 많은 오류를 용서합니다. 특히 TypeScript를 사용하면 유형을 자동으로 추론할 수 없는 경우에도 변수 유형을 지정하지 않을 수 있습니다. any 문제는 예를 들어 함수 인수에 변수 유형을 지정하는 것을 실수로 잊어버릴 수 있다는 것입니다. 오류를 표시하는 대신 TypeScript는 자동으로 변수 유형을 로 추론합니다. any function parse(str) { // ^? any return str.split(''); } // TypeError: str.split is not a function const res1 = parse(42); const res2 = parse('hello'); // ^? any 컴파일러 옵션을 활성화하면 컴파일러는 변수 유형이 자동으로 로 유추되는 모든 위치를 강조 표시합니다. 이 예에서 TypeScript는 함수 인수의 유형을 지정하라는 메시지를 표시합니다. noImplicitAny any function parse(str) { // ^ Error: Parameter 'str' implicitly has an 'any' type. return str.split(''); } 유형을 지정하면 TypeScript는 문자열 매개변수에 숫자를 전달하는 오류를 빠르게 포착합니다. 변수에 저장된 함수의 반환 값도 올바른 유형을 갖습니다. res2 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[] Catch 변수의 알 수 없는 유형 { "compilerOptions": { "useUnknownInCatchVariables": true } } 구성하면 try-catch 블록에서 예외를 안전하게 처리할 수 있습니다. 기본적으로 TypeScript는 catch 블록의 오류 유형이 라고 가정하므로 오류에 대해 무엇이든 할 수 있습니다. useUnknownInCatchVariables any 예를 들어, 발견된 오류를 있는 그대로 인스턴스를 허용하는 로깅 함수에 전달할 수 있습니다. Error function logError(err: Error) { // ... } try { return JSON.parse(userInput); } catch (err) { // ^? any logError(err); } 그러나 실제로는 오류 유형에 대한 보장이 없으며 오류가 발생한 런타임 시에만 오류의 실제 유형을 확인할 수 있습니다. 로깅 함수가 가 아닌 것을 수신하면 런타임 오류가 발생합니다. Error 따라서 옵션은 오류 유형을 에서 으로 전환하여 작업을 수행하기 전에 오류 유형을 확인하도록 상기시킵니다. useUnknownInCatchVariables any unknown 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')); } } 이제 TypeScript는 변수를 함수에 전달하기 전에 해당 변수의 유형을 확인하라는 메시지를 표시하여 더 정확하고 안전한 코드를 생성합니다. 불행하게도 이 옵션은 함수나 콜백 함수의 입력 오류에는 도움이 되지 않습니다. err logError promise.catch() 하지만 다음 기사에서는 경우에 대처하는 방법을 논의할 것입니다. any 호출 유형 확인 및 적용 방법 { "compilerOptions": { "strictBindCallApply": true } } 또 다른 옵션은 및 통해 내 호출의 모양을 수정합니다. 이는 처음 두 경우보다 덜 일반적인 경우이지만 여전히 고려하는 것이 중요합니다. 기본적으로 TypeScript는 이러한 구성의 유형을 전혀 확인하지 않습니다. call apply any 예를 들어 함수의 인수로 무엇이든 전달할 수 있으며 결국에는 항상 유형을 받게 됩니다. any function parse(value: string) { return parseInt(value, 10); } const n1 = parse.call(undefined, '10'); // ^? any const n2 = parse.call(undefined, false); // ^? any 옵션을 활성화하면 TypeScript가 더 똑똑해 지므로 반환 유형이 로 올바르게 추론됩니다. 그리고 잘못된 유형의 인수를 전달하려고 하면 TypeScript는 오류를 가리킵니다. strictBindCallApply number 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'. 실행 컨텍스트에 대한 엄격한 유형 { "compilerOptions": { "noImplicitThis": true } } 프로젝트에 나타나는 방지하는 데 도움이 될 수 있는 다음 옵션은 함수 호출의 실행 컨텍스트 처리를 수정합니다. JavaScript의 동적 특성으로 인해 함수 내부의 컨텍스트 유형을 정적으로 결정하기가 어렵습니다. any 기본적으로 TypeScript는 이러한 경우 컨텍스트에 유형을 사용하고 경고를 제공하지 않습니다. any 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 Person name TypeScript의 Null 및 정의되지 않은 지원 { "compilerOptions": { "strictNullChecks": true } } 다음으로 모드에 포함된 여러 옵션은 코드베이스에 유형도 나타나지 않습니다. 그러나 TS 컴파일러의 동작을 더욱 엄격하게 만들고 개발 중에 더 많은 오류가 발견될 수 있도록 합니다. strict any 첫 번째 옵션은 TypeScript에서 및 처리를 수정합니다. 기본적으로 TypeScript는 및 모든 유형에 대해 유효한 값이라고 가정하므로 예기치 않은 런타임 오류가 발생할 수 있습니다. null undefined null undefined 컴파일러 옵션을 활성화하면 개발자는 및 경우가 발생할 수 있는 경우를 명시적으로 처리해야 합니다. strictNullChecks null undefined 예를 들어 다음 코드를 고려해보세요. 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 이 코드는 오류 없이 컴파일되지만 "Max"라는 이름의 사용자가 시스템에 존재하지 않고 반환하는 경우 런타임 오류가 발생할 수 있습니다. 이를 방지하기 위해 컴파일러 옵션을 활성화할 수 있습니다. users.find() undefined strictNullChecks 이제 TypeScript는 에 의해 반환되는 또는 가능성을 명시적으로 처리하도록 강제합니다. users.find() null undefined const loggedInUser = users.find(u => u.name === 'Max'); // ^? { name: string; age: number; } | undefined if (loggedInUser) { console.log(loggedInUser.age); } 및 가능성을 명시적으로 처리함으로써 런타임 오류를 방지하고 코드가 더욱 강력하고 오류가 없는지 확인할 수 있습니다. null undefiined 엄격한 함수 유형 { "compilerOptions": { "strictFunctionTypes": true } } 활성화하면 TypeScript의 컴파일러가 더욱 지능화됩니다. 버전 2.6 이전에는 TypeScript가 함수 인수의 확인하지 않았습니다. 잘못된 유형의 인수를 사용하여 함수를 호출하면 런타임 오류가 발생합니다. strictFunctionTypes 반공변성을 예를 들어, 함수 유형이 문자열과 숫자를 모두 처리할 수 있더라도 문자열만 처리할 수 있는 해당 유형에 함수를 할당할 수 있습니다. 여전히 해당 함수에 숫자를 전달할 수 있지만 런타임 오류가 발생합니다. 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); 다행히 옵션을 활성화하면 이 동작이 수정되고, 컴파일러는 컴파일 타임에 이러한 오류를 포착하여 함수의 유형 비호환성에 대한 자세한 메시지를 표시할 수 있습니다. strictFunctionTypes 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'. 클래스 속성 초기화 { "compilerOptions": { "strictPropertyInitialization": true } } 마지막으로 옵션을 사용하면 값을 값으로 포함하지 않는 유형에 대한 필수 클래스 속성 초기화를 확인할 수 있습니다. strictPropertyInitialization undefined 예를 들어 다음 코드에서는 개발자가 속성을 초기화하는 것을 잊었습니다. 기본적으로 TypeScript는 이 오류를 감지하지 않으며 런타임에 문제가 발생할 수 있습니다. email class UserAccount { name: string; email: string; constructor(name: string) { this.name = name; // Forgot to assign a value to this.email } } 그러나 옵션이 활성화되면 TypeScript는 이 문제를 강조 표시합니다. strictPropertyInitialization email: string; // ^ Error: Property 'email' has no initializer and // is not definitely assigned in the constructor. 안전한 인덱스 서명 { "compilerOptions": { "noUncheckedIndexedAccess": true } } 옵션은 모드의 일부는 아니지만 프로젝트의 코드 품질을 향상시키는 데 도움이 될 수 있는 또 다른 옵션입니다. 이를 통해 인덱스 액세스 표현식에 또는 반환 유형이 있는지 확인하여 런타임 오류를 방지할 수 있습니다. noUncheckedIndexedAccess strict null undefined 캐시된 값을 저장하기 위한 객체가 있는 다음 예제를 고려해보세요. 그런 다음 키 중 하나의 값을 얻습니다. 물론 원하는 키의 값이 실제로 캐시에 존재한다는 보장은 없습니다. 기본적으로 TypeScript는 값이 존재하고 유형을 갖는다고 가정합니다. 이로 인해 런타임 오류가 발생할 수 있습니다. string const cache: Record<string, string> = {}; const value = cache['key']; // ^? string console.log(value.toUpperCase()); // ^ TypeError: Cannot read properties of undefined TypeScript에서 옵션을 활성화하려면 반환 유형에 대한 인덱스 액세스 표현식을 확인해야 하며, 이는 런타임 오류를 방지하는 데 도움이 될 수 있습니다. 이는 배열의 요소에 액세스하는 경우에도 적용됩니다. noUncheckedIndexedAccess undefined const cache: Record<string, string> = {}; const value = cache['key']; // ^? string | undefined if (value) { console.log(value.toUpperCase()); } 권장 구성 논의된 옵션에 따라 최적의 유형 안전성을 위해 프로젝트의 파일에서 및 옵션을 활성화하는 것이 좋습니다. tsconfig.json strict noUncheckedIndexedAccess { "compilerOptions": { "strict": true, "noUncheckedIndexedAccess": true, } } 옵션을 이미 활성화한 경우 옵션이 중복되지 않도록 다음 옵션을 제거하는 것이 좋습니다. strict strict: true noImplicitAny useUnknownInCatchVariables strictBindCallApply noImplicitThis strictFunctionTypes strictNullChecks strictPropertyInitialization 또한 유형 시스템을 약화시키거나 런타임 오류를 일으킬 수 있는 다음 옵션을 제거하는 것이 좋습니다. keyofStringsOnly noStrictGenericChecks suppressImplicitAnyIndexErrors suppressExcessPropertyErrors 이러한 옵션을 신중하게 고려하고 구성하면 TypeScript 프로젝트에서 최적의 유형 안전성과 더 나은 개발자 경험을 얻을 수 있습니다. 결론 TypeScript는 컴파일러와 유형 시스템을 지속적으로 개선하면서 많은 발전을 이루었습니다. 그러나 이전 버전과의 호환성을 유지하기 위해 TypeScript 구성은 유형 검사 품질에 큰 영향을 미칠 수 있는 옵션이 많아 더욱 복잡해졌습니다. 이러한 옵션을 신중하게 고려하고 구성하면 TypeScript 프로젝트에서 최적의 유형 안전성과 더 나은 개발자 경험을 얻을 수 있습니다. 프로젝트 구성에서 어떤 옵션을 활성화하고 제거할지 아는 것이 중요합니다. 특정 옵션을 비활성화하면 결과를 이해하면 각 옵션에 대해 정보를 바탕으로 결정을 내릴 수 있습니다. 엄격한 입력으로 인해 결과가 발생할 수 있다는 점을 명심하는 것이 중요합니다. JavaScript의 동적 특성을 효과적으로 처리하려면 단순히 변수 뒤에 "숫자" 또는 "문자열"을 지정하는 것 이상으로 TypeScript에 대한 충분한 이해가 필요합니다. 발생할 유형 관련 문제를 보다 효과적으로 해결하려면 더 복잡한 구조와 TypeScript 우선 라이브러리 및 도구 생태계에 익숙해져야 합니다. 결과적으로 코드를 작성하려면 조금 더 많은 노력이 필요할 수 있지만, 내 경험에 따르면 이러한 노력은 장기 프로젝트에서는 그만한 가치가 있습니다. 이 기사에서 새로운 것을 배웠기를 바랍니다. 이것은 시리즈의 첫 번째 부분입니다. 다음 기사에서는 TypeScript 표준 라이브러리의 유형을 개선하여 더 나은 유형 안전성과 코드 품질을 달성하는 방법에 대해 논의하겠습니다. 계속 지켜봐 주시기 바랍니다. 읽어주셔서 감사합니다! 유용한 링크 TSConfig 참조 어떤 유형 널(Null) 및 정의되지 않음