[ 살펴보기 ] Typescirpt - compilerOptions ( type checking )
![[ 살펴보기 ] Typescirpt - compilerOptions ( type checking )](https://cdn.hashnode.com/res/hashnode/image/upload/v1725803516389/ce067df6-0ac2-496c-a33a-6d03a71355ab.jpeg)
Typescript compiler가 typescript를 compile할 때 tsconfig에 있는 정보를 토대로 어떤 파일을 포함할 것인지, 혹은 제외할 것이지 또는 어떤 규칙들을 적용하여 type 검사를 할 것인지 결정한다.
tsconfig에 설정할 수 있는 option은 굉장히 다양하고 설정 값에 따라 typesciprt로 code를 하는 경험도 굉장히 많이 달라질 수 있다. 해당 포스트를 통해 compiler option중 type checking과 관련된 옵션을 살펴보자.
allowUnreachableCode
unreachable code가 존재할 때 compile시 오류를 발생 여부를 정한다. undefiend이 default이며 false로 설정되면 unreacheable code가 있을 때 compile시 에러가 발생한다. 예를 들어 다음과 같은 코드는 unreachable code로 취급된다.
// tsconfig.json
{
"compilerOptions": {
"allowUnreachableCode": undefined, // ( default - undefined )
...
}
}
// index.ts
function fn(n: number) {
if (n > 5) {
return true;
} else {
return false;
}
return true; // unreachable code
}
alwaysStrict
typescript를 compile할 때 strict mode에 기반하여 코드를 분석하고 결과 파일에 "use strict"를 추가한다. 다만 ES module은 default로 strict mode가 적용되므로 결과가 es module로 compile된다면 "use strict"가 별개로 추가되지는 않는다.
// tsconfig.json
{
"compilerOptions": {
"alwaysStrict": true, // ( default - true )
...
}
}
noFallthroughCasesInSwitch
switch의 모든 case에서 return 또는 break 또는 throw가 적용되어 있는가를 점검한다. 만약 config가 아래와 같다면 switch의 case 0번에 return이나 break 구분이 없으므로 compile시 에러가 발생한다.
// tsconfig.json
{
"compilerOptions": {
"noFallthroughCasesInSwitch": true,
...
}
}
// index.ts
switch (personAge) {
case 0:
console.log("even");
case 1:
console.log("odd");
break;
}
noImplicitAny
암묵적인 any type을 허용할 것인지 설정한다.
// tsconfig.json
{
"compilerOptions": {
"noImplicitAny": false,
...
}
}
// index.ts
const testInfo = (name) => {
return name;
};
위의 예제에서 testInfo 함수가 받는 인자는 암묵적으로 any type으로 취급되고 noImplicitAny option이 false로 되어있으므로 type 오류가 발생하지 않는다.
하지만 noImplicitAny option을 true로 변경하면 암묵적인 any type을 허용하지 않으므로 위 코드는 타입 에러가 발생한다.
noImplicitOverride
자식 클래스가 부모 클래스의 method를 override할 때 암묵적인 override를 방지한다. 즉, 자식 클래스에서 부모 클래스의 method를 overrider할 때 override keyword 사용을 강제한다.
// tsconfig.json
{
"compilerOptions": {
"noImplicitOverride": true,
...
}
}
// index.ts
class Album {
download() {
...
}
}
class SharedAlbum extends Album {
override download() {
...
}
}
위의 예제에서 SharedAlbum 클래스가 부모 클래스인 Album의 download method를 override하고 있다. noImplicitOverride 설정이 true로 설정 되어 있으므로 만약 override keyword를 생략하면 compile시 타입 오류가 발생한다.
noImplicitReturns
함수의 암묵적 return 허용 여부를 정한다. Javascript는 함수에서 아무것도 return되지 않으면 default로 undefined이 return되지만 이 옵션을 true로 설정하면 함수에서 조건문을 통해 값을 return할 때 모든 경우에 명시적으로 값을 return 해주어야 한다.
// tsconfig.json
{
"compilerOptions": {
"noImplicitReturns": true,
...
}
}
// index.ts
const testInfo = (name?: string) => {
if (name) {
return name;
}
};
위의 코드를 compile하면 에러가 발생한다. Javascript 함수는 아무 값도 return하지 않으면 default로 undefiend을 return하지만 noImplicitReturns을 true로 설정 하였으므로 모든 조건에 return을 명시적으로 선언해주어야 한다.
const testInfo = (name?: string) => {
if (name) {
return name;
}
return undefined;
};
noImplicitThis
this expression이 implicit any 타입을 가질 때 type error를 발생 시킬지 여부를 정한다.
// tsconfig.json
{
"compilerOptions": {
"noImplicitThis": true,
...
}
}
// index.ts
class TestClass {
testVal: string;
constructor(val: string) {
this.testVal = val;
}
getTest() {
this.testVal = "";
return function () {
return this.testVal; // type error 발생
};
}
}
위의 예제에서 getTest method가 return하는 함수 내의 this는 TestClass context의 this가 아니므로 implicit any로 취급되며 type error가 발생한다.
noPropertyAccessFromIndexSignature
index signature를 포함하는 type을 사용하는 객체 데이터 중 명시적으로 선언되지 않은 property에 접근할 때 dot( object.key ) 문법이 아닌 indexed 문법을( obj["key"] ) 사용하도록 강제한다.
// tsconfig.json
{
"compilerOptions": {
"noPropertyAccessFromIndexSignature": true,
...
}
}
// index.ts
type RobotModel = {
color: string;
[key: string]: string;
}
const getRobotModel = (): RobotModel => {
return { color: "blue", size:"big" };
};
const robot = getRobotModel();
const testValDot = robot.size; // type error
const testValIndexed = robot["size"];
위의 예제와 같이 noPropertyAccessFromIndexSignature 옵션이 true일 때는 type에 명시적으로 선언된 type이 아닌 index signature로 인해 허용된 임의의 property에 접근할 때는 위의 예제와 같이 indexed 문법이 아닌 dot 문법을 통해 임의의 property에 접근하면 type 오류가 발생한다.
noUnusedLocals
선언했지만 사용하지 않는 local 변수가 있으면 type error를 발생시킨다.
// tsconfig.json
{
"compilerOptions": {
"noUnusedLocals": true,
...
}
}
// index.ts
const getRobotModel = (): RobotModel => {
const test = "123";
...
};
위의 예제에서 test local 변수를 선언했지만 사용하는 곳이 없기에 typescript compile시 type error가 발생한다.
noUnusedParameters
함수가 전달 받는 인자 중 실제로 사용하지 않는 인자가 있으면 type error를 발생시킨다.
// tsconfig.json
{
"compilerOptions": {
"noUnusedParameters": true,
...
}
}
// index.ts
const getRobotModel = (title: string): RobotModel => {
...
};
위의 예제에서 getRobotModel 함수는 title 인자를 받지만 함수 내에서 실제로 사용하지 않고 있기에 typescript compile시 type error가 발생한다.
strict
strict 옵션을 true로 설정하면 alwaysStrict, strictNullChecks, noImplicitAny등 보다 strict한 type 체크를 위해 필요한 여러가지 설정들을 모두 true로 설정한다.
strict를 true로 설정했을 때 다음 설정들이 모두 true로 설정된다.
alwaysStrict
strictNullChecks
strictBindCallApply
strictFunctionTypes
strictPropertyInitialization
noImplicitAny
noImplicitThis
useUnknownInCatchVariable
만약 strict 설정으로 함께 true로 설정되는 설정 중 일부를 false로 변경하고 싶으면 strict를 true로 설정한 채로 해당 설정만 false로 변경하면 된다.
// tsconfig.json
{
"compilerOptions": {
"strict": true,
"noImplicitThis":false // 해당 설정만 false로 전환
...
}
}
strictBindCallApply
call, apply, bind를 통해 함수에 특정 객체를 바인딩할 때 추가로 전달하는 parameter가 해당 함수가 전달받는 parameter와 type이 일치하는지 점검한다.
// tsconfig.json
{
"compilerOptions": {
"strictBindCallApply": true,
...
}
}
// index.ts
const getRobotModel = function (title: string) {
// bind한 this에 접근하기 위해 arrow function은 사용하지 않는다.
return { color: this.color, title };
};
const defaultRobot = {
color: "green",
};
const robotA = getRobotModel.bind(defaultRobot, "robot title");
const robotB = getRobotModel.bind(defaultRobot, 22); // type error
위의 예제에서 robotB 변수는 bind method를 통해 바인딩을 수행할 때 바인딩 대상( getRobotModel )이 전달 받는 인자( title:string )와 다른 type의 데이터를 전달하고 있으므로 type error가 발생한다.
strictFunctionTypes
함수의 인자에 대해 보다 엄격한 type check를 적용한다.
// tsconfig.json
{
"compilerOptions": {
"strictFunctionTypes": false,
...
}
}
// index.ts
const getRobotModel = (title: string): RobotModel => {
return {
color: "green",
size: "big",
title: title.toLocaleLowerCase(),
};
};
type TestRobotModel = (param: string | number) => RobotModel;
const testFn: TestRobotModel = getRobotModel;
위의 예제와 같이 strictFunctionTypes option이 false일 땐 getRobotModel 함수의 인자가 string 이므로 TestRobotModel type의 인자 type ( string | number )는 만족하기에 타입 오류가 발생하진 않는다.
하지만 strictFunctionTypes option을 true로 설정하면 함수 인자에 대한 보다 엄격탄 type check가 적용되며 TestRobotModel type은 더 이상 getRobotModel 함수를 허용하지 않는다. ( 인자의 타입이 정확히 일치해야 한다 )
strictNullChecks
다음과 같은 상황을 고려해 보자.
const testRobot = [
{ name: "test1", price: 1000 },
{ name: "test2", price: 2000 },
];
const robotFound = testRobot.find((item) => item.price > 3000);
const robotName = robotFound.name
위의 상황에서 robotFound 변수는 undefined이기에 name 속성에 접근하려고 하면 runtime error가 발생한다. 위의 예제와 같이 name property에 접근하려면 robotFound라는 object가 반드시 존재해야 하지만 위와 같은 상황은 robotFound 변수가 undefined이 될 수도 있는 상황이다. strictNullChecks 옵션은 이러한 상황에서 type 에러를 발생 시켜준다.
// tsconfig.json
{
"compilerOptions": {
"strictNullChecks": true,
...
}
}
// index.ts
const testRobot = [
{ name: "test1", price: 1000 },
{ name: "test2", price: 2000 },
];
const robotFound = testRobot.find((item) => item.price > 3000);
const robotName = robotFound.name // type error 발생
strictPropertyInitialization
Typescirpt class에서 선언은 되어 있지만 default value 설정도 되지 않고 constructor에서 초기화도 되지 않는 property가 있다면 type error를 발생 시킨다.
// tsconfig.json
{
"compilerOptions": {
"strictNullChecks":true,
"strictPropertyInitialization": true,
...
}
}
// index.ts
class Robot {
color: string; // type error 발생
size: string = "big";
price:number;
constructor(color: string, size: string, price:number) {
this.price = price;
}
}
위의 예제에서 color property는 선언은 되었지만 default 값도 없고 constructor에서 초기화 되지도 않으므로 type error가 발생한다.
strictPropertyInitialization 옵션을 사용하기 위해선 strictNullChecks 옵션이 true로 설정되어 있어야 한다.
useUnknownInCatchVariables
try catch statement에서 error의 type이 any가 아닌 unknown으로 설정한다. catch문에 전달된 error가 Error 객체 또는 Error 객체의 sub-class 객체가 아닐 수 있으므로 기존 any타입을 통해 Error 객체일 것이라 가정하고 catch문을 처리하는 것은 자칫 위험할 수 있다. useUnknownInCatchVariables 설정은 catch문의 error를 unknown type으로 변경하여 catch 문에서도 보다 안전한 타입 체크를 통해 error 처리를 하게 해준다.
// tsconfig.json
{
"compilerOptions": {
"useUnknownInCatchVariables":true,
...
}
}
// index.ts
try {
...
} catch (err) {
if (err instanceof Error) {
console.log(err.message);
}
}
위의 예제에선 catch문의 error가 Error 객체의 instance인지 확인하고 message property에 접근하고 있다.
![[ 살펴보기 ] RDB - Relationships](https://cdn.hashnode.com/res/hashnode/image/upload/v1739711556668/48dc9e84-a621-42aa-9c9f-5fc5c436f0ec.jpeg)
![[ 살펴보기 ] MySQL - Data types](https://cdn.hashnode.com/res/hashnode/image/upload/v1739593589113/530f8704-4d27-42c9-a451-bb5c63150b99.jpeg)
![[ 살펴보기 ] TypeORM - Transactions, Migration](https://cdn.hashnode.com/res/hashnode/image/upload/v1739106042581/980b8133-61d4-406a-a026-65be9c28eace.jpeg)
![[ 살펴보기 ] TypeORM - Relations](https://cdn.hashnode.com/res/hashnode/image/upload/v1738666874402/b688bd0b-b6bb-4f43-87d8-c1b46b59f1b7.jpeg)
![[ 살펴보기 ] TypeORM - Basics](https://cdn.hashnode.com/res/hashnode/image/upload/v1738666803591/bef5df17-7dc7-4123-ae55-004d5042df39.jpeg)