프론트엔드 데브코스 TIL #DAY41

에구마·2023년 11월 14일
2

📚 23.11.14

  • 모듈의 타입선언
  • 타입 가져오기 내보내기
  • tsconfig.json

모듈의 타입 선언 - 모듈 활용

이미 만들어진 기능, 즉 모듈을 활용할 수 있는데 이 때 타입을 지정해주어야 한다.

  • 먼저, 모듈을 불러오고 이에 대해 타입을 직접 지정하는 방법!

string을 camelCase로 바꾸는 모듈인 ladish 모듈을 설치한다 npm i lodash

// /src/lodash.d.ts
declare module "lodash" {
  interface Lodash {
    camelCase(str: string): string;
  }
  const _: Lodash;
  export default _;
}
import _ from "lodash";

const str = "I drink coffee";
const newStr = _.camelCase(str);
console.log(newStr);

tsconfig.json에서 해당 파일을 읽을 수 있도록 include에 경로를 추가해주면,
문제없이 사용이 가능해진다!

  • 만들어져있는 타입 모듈을 불러와 사용할 수도 있다.

npm i @types/lodash - D

그러면 lodash.d.ts 파일 없어도 불러와 쓸 수 있다!

하지만 이렇게 패키지를 설치하여 사용할때 import _ 이부분에 에러가 난다.
기본내보내기 구조로 타입이 선언되어있지 않기 때문이다

이에 대한 해결로

  1. *

    import * as _ from 'lodash'

    기본내보내기 구조가 아닌 패키지 내용도 가져올 수 있게 됨!

  2. tsconfig.json의 “compilerOptions”에 “esModuleInterop” : true // 기본 false



모듈의 타입 선언 - 프로젝트 내 js 모듈

프로젝트 내부에 이미 존재하는 자스 모듈을 어떻게 타입선언하는지 알아보자!

ts파일에서 js파일을 직접 가져오는 걸 허용하려면
tsconfig.json에서 “allowJs” : true

하지만 자바스크립트 모듈의 타입이 다 any로 해석되는 문제가 있다!!
해결하려면!

최소한의 타입을 제공하자!

  1. 해당 js파일 주변에 같은이름.d.ts파일을 만든다. 로직이 아니라 타입만 들어있는 파일이다!

  2. ~.d.ts 파일엔 js파일의 내용에 대해 타입을 만들어주자. 구현부는 관심없음

    // myUtils.js
    interface Add {
     (a: number, b: number): number;
    }
    interface Substract {
     (a: number, b: number): number;
    }
    export const add: Add;
    //
    // myUtils.d.ts
    interface Add {
     (a: number, b: number): number;
    }
    interface Substract {
     (a: number, b: number): number;
    }
    export const add: Add;
    export const subtract: Subtract;
  3. tsconfig.json에 /js/**/*.ts 경로 include

그럼 main.ts에서 다음과 같이 사용가능하다!

import { add } from "../js/myUtils";

const a = add(1, 2);

기본 내보내기(default)도 적용해보자

//myUtils.js
.. 동일
export default {
 add,
 subtract,
};
// main.ts
import utils, { add, subtract } from "../js/myUtils";
const a = add(1, 2);
const b = utils.add(3, 4); //

타입선언파일 (.d.ts)에서 명시적으로 기본내보내기에 타입을 지정한다면?

//...동일
interface DefaultExport {
 add: Add;
 subtract: Subtract;
}
export default DefaultExport;

=> main.ts에서 'utils' only refers to a type, but is being used as a value here.
기본내보내기 된 DefaultExport는 타입이니까! .add가 안돼!
declare를 사용하여 선언해야한다!!
다음과 같이 수정해야한다

declare const de : DefaultExport
export default de; //

다른 폴더에서 d.ts를 만들어야한다면?

위의 경우엔 /js/myUtils.d.ts , /js/myUtils.js 그리고 /src/main.ts 의 폴더구조였다.
하지만, d.ts파일과 js파일이 같은 폴더에 있지 않고 따로 d.ts를 모아두는 등 경로가 다르다면 ??

  1. 원하는 위치에(주로 /types/) d.ts 파일을 만든다. 이때 파일명은 js모듈파일과 같지 않아도 된다!

  2. d.ts 파일에서 module로 declare를 해줘야한다. 여기서 해당 모듈이름사용.
    내부에 declare는 지운다.

    declare module "myUtils" { //
     interface Add {
       (a: number, b: number): number;
     }
     interface Subtract {
       (a: number, b: number): number;
     }
     export const add: Add;
     export const subtract: Subtract;
    
     interface DefaultExport {
       add: Add;
       subtract: Subtract;
     }
     const de: DefaultExport; //
     export default de;
    }
  3. tsconfig.json에 해당 경로를 추가한다.

    "compilerOptions: : { ... , "paths" : [ "myUtils" : ["./js/myUtils.js"]}},
    "include" : [ ..., “types/**/*.ts” ]
  4. main.ts에서 위에 지정한 경로(경로별칭!)으로부터 가져온다.

    import utils, {add, subtract} from 'myUtils' // 


타입 가져오기와 내보내기

ts에선 값 뿐만 아니라 “타입”도 가져오고 내보낼 수 있다!

타입내보내기와 import type

// src/myUtils.ts
export interface Add {
	(a: number, b: number): number
}

// src/main.ts
import {Add} from './myUtils'
const newAdd : Add = (x,y) => x + y

// 데이터를 가져오는 것과 구분하려면
import type { Add } from './myUtils'

default (기본 내보내기) 사용

// src/myUtils.ts
/// .. 동일
export default {
	name : 'My utils',
	add,
	subtract
}

// src/main.ts
import utils, { add, subtract } from './myUtils'  
import type { Add, Substract } from './myUtils' // type을 붙여서 명시

const c = utils.add(4,7) // 11

이렇게 add, substract, name 은 앞에 utils.에 붙어야 사용가능하다.
각 멤버는 utils라는 네임스페이스 안에서 사용한다는 것.
타스의 타입도 네임스페이스를 정해줄 수 있다!

네임스페이스

// src/myUtils.ts

export namespace Utils { // 네임스페이스!
	export interface Add { // export 붙어있어야함!!!
		(a: number, b: number): number
	}
	export interface Subtract {
		(a: number, b: number): number
	}
}

export const add : Utils.Add = (a, b) => a + b // number
export const subtract : Utils.Subtract = (a, b) => a - b // number

export default {
	name : 'My utils',
	add,
	subtract
}
// src/main.ts

import utils, { add, subtract } from './myUtils'  
import type { Utils } from './myUtils' // type을 붙여서 명시

const c = utils.add(4,7) // 11

/// Utils를 사용하는것은
const newAdd : Utils.add = (x,y) => x+y
newAdd(1,2) // 3

확장자를 명시하지 않는 이유

“allowImportingTsExtensions”라는 옵션을 추가하지 않았다면, 확장자를 명시하지 않는다.
ts는 결국 js로 변환되어야하기 때문에, ts로 명시해버리면 변환 후에 해당 파일을 찾지 못하는 문제가 생기기 때문이다.



tsconfig.json 옵션

compilerOptions

ts→js 변환할때 어떻게 할 것인지에 대한 옵션

  • strict : false

    엄격한 타입 검사 활성화,
    true 설정시, 암시적 any,this 타입 제한, 엄격한 null,undefined,함수의매개변수 타입 검사, 엄격한 클래스의 속성 초기화 검사, 엄격한 ‘bind’,’call’,’apply’ 메소드 인수 검사

  • target
    컴파일 될 ES(JS)버전 암시. 권장 ‘ES2015’

  • lib

    컴파일에서 사용할 라이브러리 지정, ‘target’ 옵션에 따라 자동으로 지정
    ex)배열.includes 는 ES2016에서 등장.

    //
    target:ES2015,
     “lib”:[ES2016, "DOM", "DOM.Iterable"] 
    // "DOM", "DOM.Iterable"는 기본으로 갖고있는 값임. lib를 지정해주려면 포함해야함!
    그 이상의 문법 쓸일이 있다면 ES2016->ES2020으로 수정
    추천하는것은
    “lib”:[”ESNext”, "DOM", "DOM.Iterable"] 
  • module

    사용할 모듈 방식 지정

    대부분 ES2015 등 ES로 사용. 그게 우리가 흔히 쓰는 import, export

  • moduleResolution

    컴파일러가 사용할 모듈 해석 방식 지정. import from 해오는 모듈을 해석할 방식을 지정하는것. 폴더인지 파일인지
    node, bundler, classic, nodenext 등이 있음.
    nodenext : Node.js의 ES 모듈 지원하는
    bundler : Vite, Webpack, Parcel 등 최신 번들러 사용, 확장자 없이도 찾음! ((추천

  • paths
    경로 별칭 지정

    "paths" : {
     "myUtils" : ["./my_modules/utils.ts"]
     "~/*" : ["./src/*"] // ~를 사용하여 import하면 /src/하위의 모든 파일에 대해서가 됨
    }
    //
    // import from에서 해당 속성값으로 지정한 "myUtils"로부터 가져온다고 지정하면 tsconfig.json
    // import { } from '~/my_modules/utils' // 
  • jsx

    JSX 출력 방식 제어

  • outDir

    “outDir” : “dist”
    js 변환 결과가 dist폴더 안에 담김

추천하는데로 쓰면
"compilerOptions : {
  "strict" : true,
  "target" : "ES2015",
  "lib" : [ES2016, "DOM", "DOM.Iterable"] ,
  "module": "ESNext",
  "moduleResoltion" : "bundler",
  • files

    ts→js 변환할 때 사용할 파일 지정 (우선순위1)

  • exclude
    제외할 경로 지정 (우선순위2)

  • include
    폴더 단위(경로)로 지정 가능 (우선순위3)

  • extends
    현재 파일인 루트경로의 tsconfig.json 외에 다른 설정json파일을 확장 사용 가능케함



타입스크립트의 내장 유틸리티 타입

별도 선업 없이 바로 사용 가능

Partial

모든 속성을 선택(?)적으로 바꿔줌. 원본이 바뀌는 것은 아님!

interface User {
  name: string;
  age: number;
}
const userA: User = { // 여기선 age 속성이 없어서 오류!
  name: "A",
};

const userB: Partial<User> = {
  name: "B",
};
interface PartialUser { // 이런 타입이 되는 셈
  name?: string;
  age?: number;
}

Required

Partial의 반대! 선택적 속성을 다 필수로 바꿔줌!

interface User {
  name?: string;
  age?: number;
}

const userB: Required<User> = { // age속성도 필수가 되기 때문에 에러
  name: "B",
};

Readonly

재할당 안됨! only read!

interface User {
  name?: string;
  age?: number;
}

const userR: Readonly<User> = { 
  name: "rr",
	age : 10,
};
userB.name = 'EE' // 에러!

Record

유니온 타입을 받아서 속성을 만들고, 그 속성이 어떤 타입이 될지를 명시하는 용도

type Names = 'Neo' | 'lewis'
type RecordNames = {
	neo : number
	lewis : number
}

const developers : Record<Names, number> = {
	neo : 12,
	lewis : 13
}

Pick

< > 로 받는 첫번째 객체 타입중 두번째로 받은 타입들에 대해서만 추출하여 새로운 객체타입 반환

const user : Pick<User , 'name' | 'email'> = { }

user의 타입이 PickUser가 되는 셈

Omit

Pick의 반대!

< > 로 받은 첫번째 객체 타입 중 두번쨰 받은 타입들을 생략! 한 새로운 객체타입 반환

const user : Omit<User , 'name' | 'email'> = { }

Exclude

유니언 타입에서 특정 타입을 제외할 수 있다!

type T = string | number | boolean

const a : Exclude<T, number> = 'only string' // string | boolean
const b : Exclude<T , number > = 1234 // string | boolean이어야 하므로 에러!!!

Extract

각 유니언에서 공통되는 타입들을 반환 (교집합!)

type T = string | number | boolean
type U = number | booelan | string[]

const a : Exclude<T, number> = 123 // number | boolean
const b : Exclude<T , number > = 1234 // string | boolean이어야 하므로 에러!!!

ReturnType

어떤 타입이 반환되는지 알아낸.

function hello(msg: string) {
	return `hello ${msg}`
}
const a : ReturnType<typeof hello> = 123 // 불가능!! string임
// 제네릭에서 typeof를 생략하면 그냥 함수가됨. 생략안돼!



🤔 오늘 회고

예상못한 일정을 만들어서 정신이 과작과작한 하루지만 햅삐

그리고 1차팀 마지막 날..
방학기간까진 1차팀이지만 암튼. 팀챗도 남고 야간코어타임도 같이할것 같긴 하지만 괜히 섭섭하고 헛헛한 기분~ 괜히 갈틱폰도 한번해주고ㅋㅋㅋ

Keep

코드리뷰 완료! 코드리뷰에 조금 익숙해진 것 같긴하다! 그 퀄리티가 어떻냐를 따져보면 아직 부끄럽지만..
강의 정리 완료!

Problem

타입스크립트 강의가 끝났는데 실습이나 추가적인 코딩을 해보지 않아서 확립이 덜 되었다. 아직 보내주면 안될것같다... 스터디랑 마이그레이션 작업 열심히 하자

Try

특강영상 올라오면 다시 듣구 정리 추가하기!!

방학을 잘 보내보자! 어떻게 잘 보내야할지에 대한 고민을 하고 계획과 실천을 기록해보기로


profile
코딩하는 고구마 🍠 Life begins at the end of your comfort zone

2개의 댓글

comment-user-thumbnail
2023년 11월 15일

예진님 코드리뷰 도움 짱짱 많이됩니다👍👍👍 즐거운 방학 되세요~!!

1개의 답글