tsconfig.json은 크게 3가지로 나뉩니다

 

compilerOptions , include, exclude

 

compilerOptions

 - Ts코드를 Js로 변환하기 위해서 필요한 옵션

include

- 컴파일할 파일 경로 목록

- 배열 데이터로 목록화해서 제공

exclude

- 컴파일에서 제외할 파일 경로 목록

 

{
  "compilerOptions": {
    //타입 스크립트를 ES2015로 변환 (ES2015 권장)
    "target": "ES2015",

    // 모듈 시스템 지정 ESNext , CommonJS , AMD 등이 있으며
    // Node js 환경에서는 CommonJS를 사용하며, 브라우저에서는 ESM 방식 (ESNext와 동일)을 사용합니다
    "module": "ESNext",

    //모듈의 해석방식 Node와 Classic이 있으며 기본값은 Node입니다.
    "moduleResolution": "Node",

    // ECMA 방식과 Common js 방식을 호환가능 여부입니다 (기본값 false)
    // ESM 과 Common 방식을 구분짓지않고 사용가능하게 가능한 true
    "esModuleInterop": true,

    // 모든 파일을 모듈로 컴파일, import 혹은 export 필수
    "isolatedModules": false,

    // 모듈 해석에 사용할 기준 경로 지정
    "baseUrl": "./",

    // 컴파일러가 참조할 타입 선언(d.ts)의 경로를 지정합니다
    "typeRoots": ["./node_modules/@types"],

    // TS를 변환(컴파일)시 내부적으로 사용할 라이브러리의 목록을 지정합니다
    // 컴파일에서 사용할 라이브러리 목록- ESNext , DOM
    "lib": ["ESNext", "DOM"],

    // 엄격한 타입 검색 활성화 여부 (기본값 false) 가능한 true 사용하기
    // Ts를 사용함으로써 보다 엄격하게 작성하기 위함 , false 사용시 Ts의 장점중 일부가 없어집니다.
    // true 사용시 아래의 옵션들 true로 바뀌며, 세부 조정 가능합니다.
    "strict": true,

    // 기본값은 false이며, strict가 true가 됨에따라 같이 바뀌는 옵션들
    // 암시적 any 타입 검사 활성화
    "noImplicitAny": false,

    // 암시적 this 타입 검사 활성화
    "noImplicitThis": false,

    // 엄격한 Nullish 타입 검사 활성화
    "strictNullChecks": false,

    // 엄격한 함수의 매개변수 타입 검사 활성화
    "strictFunctionTypes": false,

    // 엄격한 클래스의 속성 초기화 검사 활성화
    "strictPropertyInitialization": false,

    // 엄격한 Bind, Call, Apply 메소드의 인수 검사 활성화
    "strictBindCallApply": false,

    // 이외에도 다른 옵션들이 더 있으며, strict에 따라서 바뀌지 않는 옵션도 존재합니다.

    //여기까지
  },
  "include": [
    // 프로젝트의 어느 위치에서  TS를 찾을 수 있는지
    "src/**/*.ts" //   src /하위 폴더의/ ts로 끝나는 파일들
  ],
  "exclude": [
    // 변환(컴파일) 제외 폴더
    "node_modules"
  ]
}

 

 

최소한의 옵션

{
  "compilerOptions": {
    "target": "ES2015", //타입 스크립트를 ES2015로 변환 (ES2015 권장)
    "module": "ESNext", // 모듈 시스템 지정 ESNext , CommonJS , AMD
    "moduleResolution": "Node", //모듈의 해석방식
    "esModuleInterop": true ,// ECMA 방식과 Commomjs 방식을 호환가능하게.
    "lib"  : ["ESNext","DOM"], // TS를 변환(컴파일)시 내부적으로 사용할 라이브러리의 목록을 지정
    "strict": true // TS를 엄격하게 사용할 것 인가.
  },
  "include": [  // 프로젝트의 어느 위치에서  TS를 찾을 수 있는지
    "src/**/*.ts" //   src /하위 폴더의/ ts로 끝나는 파일들
  ] ,
  "exclude": [ // 변환(컴파일) 제외 폴더
    "node_modules"
  ]
}

추론과 명시적 타입 선언

타입 추론은 코드 작성을 보다 간단하게 만들어주지만, 코드를 읽고 이해하기 어려울 수 있으며,

추론이 실패하는 경우가 있어 코드 안정성이 떨어집니다.

 

반면에, 명시적 타입 선언은 코드를 작성하고 읽는 과정에서 명확히 알려주고 가독성을 높이고, 컴파일시 타입 에러를 사전에 방지해줍니다.

하지만 타입을 명시적으로 선언하는 과정이 번거로울 수 있습니다.

 

간단한 함수에서는 타입 추론을 사용하고, 복잡한 함수나 인터페이스에서는 명시적 타입 선언을 사용하는등

적절히 선택하는 것이 중요합니다.

근대 그 적절히가 어려운 것 같습니다...

 

제네릭을 사용하며 명시적인 타입 지정을 할 경우


1.  제네릭을 사용하는 함수나 클래스가 다른 함수나 클래스와 협업하여 동작할 때

타입 추론만으로는 제대로 동작하지 않을 수 있습니다.  이런 경우에는 명시적으로 타입을 지정해주어야 합니다. 

Promise 객체를 반환하는 함수를 작성할 때는 Promise의 resolve 값의 타입을 명시적으로 지정해주어야 합니다.

2. 제네릭 타입이 여러 개 사용되는 경우 명시적으로 타입을 지정해주어야 합니다. 

React에서 제공하는 React.Component 클래스를 상속받는 경우, 제네릭 타입을 두 개 사용해야 합니다. 

이때, 두 개의 제네릭 타입이 서로 다른 타입을 나타내는 경우, 각각의 제네릭 타입을 명시적으로 지정해주어야 합니다.

3. 코드의 가독성을 높이기 위해 명시적으로 타입을 지정해주는 것이 좋을 수 있습니다. 

코드가 길어지고 복잡해질수록 타입 추론만으로는 코드를 이해하기 어려울 수 있습니다. 

이럴 때는 명시적으로 타입을 지정해주어 코드의 가독성을 높일 수 있습니다.

extends를 사용해 들어올 타입을 제한할 수 있습니다.

//제네릭
// 인터페이스, 제약 조건


//string , number만 받는다 라는 의미
interface MyData<T extends string | number>{
  name: string;
  value :T
}

const dataA: MyData<string> = {
  name: 'Data A',
  value: 'Hello world'
}

const dataB: MyData<number> = {
  name: 'Data A',
  value: 2342
}

const dataC: MyData<boolean> = {
  name: 'Data A',
  value: false
}

const dataD: MyData<number[]> = {
  name: 'Data A',
  value: [1,2,3,4]
}

 

크게 다르지 않아서 소스코드만 첨부하겠습니다.

 

//제네릭 클래스

class User<P> {
  constructor(public payload: P) {}

  getPayload() {
    return this.payload;
  }
}

interface UserAType {
  name: string;
  age: number;
  isValid: boolean;
}

interface UserBType {
  name: string;
  age: number;
  emails: string[];
}

const jplum = new User<UserAType>({
  name: "J-plum",
  age: 53492,
  isValid: true,
  emails: [], //에러 발생 UserAType 에는 emails가 없음
});

const euang = new User<UserBType>({
  name: "Eunag",
  // age가 없어서 에러 발생
  emails: ["euang@gamil.com"],
});

Ts의 제네릭 문법에서는  크게 보면 함수, 클레스, 인터페이스에서 사용할 수 있습니다

 

 

1. 함수

제네릭 클래스와 인터페이스는 아래의 링크를 참고하시면 됩니다.

제네릭 클래스 : https://j-plum.tistory.com/71

제네릭 인터페이스 : https://j-plum.tistory.com/72

 

 

array를 다양한 타입으로 오버로딩 한 상태입니다.

제네릭 문법

오버로딩으로 타입을 지정했던 부분을 전부 지워버린 상태입니다.

 

그런대 첫번재 array에서 숫자 부분에 에러가 발생했습니다.

string이라고 지정하지 않았지만 추론에 의해 string 이 아니라는 에러가 발생했습니다.

 

array<T>(x : T, y: T) 라는 구조에 의해 

 

x가 T의 타입을 사용하는데 x에 string이 넘어와 y또한 string이라고 Ts가 추론을 합니다.

 

순서를 바꿨더니 이번엔 뒤의 문자열에 에러가 발생했습니다.

 

 

추론이 아닌 미리 타입을 작성할 경우 아래와 같이 작성합니다.

string이 T에 해당하며 , x와 y는 T의 타입인 string 타입이 됩니다.

 

 


소스코드

interface Object {
  a: number;
}

type Arr = [number, number];

// function array(x: string, y: string): string[];
// function array(x: number, y: number): number[];
// function array(x: boolean, y: boolean): boolean[];
// function array(x: Object, y: Object): Object[];
// function array(x: Arr, y: Arr): Arr[];


function array<T>(x: T, y: T){
  return [x, y];
}

console.log(
  array('J-plum','Euang'),
  array(1,2),
  array(true,false),
  array({ a: 1 },{a: 2}),
  array([1,2],[3,4,5]), // 이와 같이 사용할 경우 number[] 타입을 추론합니다.
  array<Arr>([1,2],[3,4,5]), // Arr을 이용하려면 튜플에 맞게 5를 지워야합니다.
)

 

클레스

클레스에서 위에 타입을 지정해주지 않으면 에러가 발생합니다.

 

js에서는 문제가 없는 코드이지만

 

Ts에서는 constructor 가 지정되기 전에 미리 타입이 지정되어 있어야합니다.

 


접근 제어자

public : 자유롭게 접근 가능, 클래스내 생략 가능

protected : 자신과 파생된 후손 클래스 내에서 접근 가능

private : 클래스 내에서만 접근 가능

 


추가내용

클래스 위에서 타입을 지정하지 않고 생성자에서 접근제어자와 함깨 작성한다면 생략 가능합니다.

(단! 이때 public은 생략할 수 없습니다.)

 

소스코드

class User1 {
  constructor(
    public first: string,
    public pet: string,
    public age: number
  ) {
    this.first = first;
    this.pet = pet;
    this.age = age;
  }
  getAge() {
    return `${this.first} ${this.pet} is ${this.age}`;
  }
}

class User2 extends User1 {
  getAge() {
    return `${this.first} ${this.pet} is ${this.age}`;
  }
}

class User3 extends User2 {
  getAge() {
    return `${this.first} ${this.pet} is ${this.age}`;
  }
}

const Jplum = new User1("J-plum", "Euang", 4236798);
console.log(Jplum.first);
console.log(Jplum.pet);
console.log(Jplum.age);

위의 이미지는 

로직과 매개변수 개수도 똑같은데 타입이 다르다는 이유로 두개로 만들어서 사용하는 이미지입니다.

 

이걸 함수의 오버로딩을 이용한다면

타입을 분기해 이용이 가능합니다.

add 함수의 any는 위의&nbsp; 타입들을 받을수 있게 만든 것입니다.

 

에러 내용 add의 두가지 형식에 해당되지 않는다.

함수를 여러개 만들지 않더라도

함수의 타입 선언부를 여러개 만들어 줌으로써(시그니처), 같은 함수라도 타입을 여러개로 관리할 수 있습니다.

 

 

아 ~ 무 문제 없어보이지만

 

우리의 Ts  에러가 발생했다.

 

이러면 또 .. Ts를 사용하는 의미가..

 

요로코롬 사용하면! 에러가 사라집니다

 

뭔가.. 저렇게 사용하면 매개변수 처럼 보이긴 하지만.. 

 

그냥 this를 지정해주었다! 라고 생각하시면 될 것 같습니다.

type 이라는 키워드를 사용해서 만듭니다.

 

type 별칭 = 타입

 

위와 같이 User 라는 타입을 만들어 버티컬 바를 사용해 유니온 타입으로 작성도 가능합니다.

 

 

만든 별칭은 아래와 같이 이용합니다.

 

 


타입별칭과 인터페이스의 차이점

1. 각각 type, interface를 통해 선언합니다.

2. type의 경우  ' = ' 할당연산자를 사용합니다

 

 

생각보다 차이가 ..

기능적으로는 차이가 없습니다. 결국 취향 차이라고 합니다

굳이 권장을 하자면 interface라고 합니다.

type 의 경우 객체의 구조를 만들기 보다는 다양한 타입의 별칭을 지정하는 용도이며

interface의 경우에는 함수, 배열등 다양하게 지정이 가능하지만 기본적으로 객체를 전제로 하기 때문입니다.

 

UserA 라는 인터페이스를 작성후

UserB 에 UserA를 extends(상속)

UserB는 name, age도 존재하는 상태가 됩니다.

 

Jplum: UserA는  UserA에 isValid 라는 속성은 없기 때문에 에러가 발생합니다.

Euang: UserB는  UserA를 UserB가 상속받았으므로 , isValid 만 있지만 . name, age또한 존재하는 상태가 됩니다.


 

+ Recent posts