노마드코더 타입스크립트 정리

js·2022년 6월 12일
0

타입스크립트

목록 보기
4/4

Typescript 특징

  • 에러가 발생할 코드를 감지하면, js로 컴파일 하지 않는다
  • 컴파일 상에서 타입 에러를 미리 잡기 위한 목적이 크다

Type

Implicit && Explicit

const a = "hello" // ts가 a를 string으로 감지. Implicit type  
const b: string = "hi" // 타입을 명시적으로 선언. Explicit type

aliases

type 키워드로 선언하는 타입

optional

? 키워드로 선언하며 해당 타입이 undefined가 될수도 있다는 의미를 가진다

interface Iobj {
	name: string,
    nickName?: string // nickName: string | undefined
}

readonly

읽기전용 속성, 수정이 불가하다

interface Iobj {
	name: string,
    readonly nickName: string 
}

const someone: Iobj = { name: 'peter', nickName: 'spiderman'};

someone.nickName = 'superman' // error

tuple

각기 다른 타입의 요소를 가지는 하나의 배열

const arr: [number, string, boolean] = [1, "strong", false]

never

반환값이 없으면서 Error를 던지거나 실행이 종료되는 함수의 타입

function someError(message: string): never {
    throw new Error(message)
}

function hello(name:string|number){
    if(typeof name ==="string"){
        name // string
    }else if(typeof name === "number"){
        name // number 
    }else{
        name // never
}
  
// union 타입에서 제거가 된다
type StrUnion = never | string

// intersection 타입에서는 덮어쓴다
type NeverInter = never & string

unknown

any 처럼 모든 타입을 허용한다.

TS에서 unknown으로 추론하는 경우는 없으니 개발자가 명시해야 한다.

assertion 혹은 타입가드와 함께 사용한다.

아래 코드에선 타입가드는typeof로 해보았다.

let a:unknown;
if (typeof a === 'number') {
    let b = a + 1
}

overloading

오버로딩으로 매개변수의 타입, 개수, 순서가 달라질 수 있다.

오버로딩을 위해 다수의 call signature를 type에 등록 시킨다.

아래와 같이, 매개변수의 개수가 달라지는 경우 optional 키워드를 적용하자.

type Add = {
    (a:number, b:number): number,
    (a:number, b:number, c:number): number
}
const add:Add=(a,b,c?:number)=>{
    if(c) return a+b+c
    return a+b
}

generic

TS는 generic을 바탕으로 call signature를 만들어 준다.

관습적으로 T, V가 많이 쓰인다.

type Player<T> = {
    name: string
    extraInfo: T
}
type NicoExtra = {
    favFood: string
}
type NicoPlayer = Player<NicoExtra>

const nico: NicoPlayer = {
	name: "nico",
	extraInfo:{
    	favFood: "kimchi"                                
    }
}
// 역으로 class에서 제네릭을 먼저 선언하고 
// interface에서 제네릭을 내려받아(?) 사용하는 케이스 

interface SStorage<T>{
	[key:string]: T
}

class LocalStorage<T>   
	private storage: SStorage<T>
    set(key:string, value:T){}
}

class

abstract

extends로 상속 받을 수 있는 클래스, 인스턴스를 만들수 없는 클래스

구현된 메서드를 포함 시킬 수 있다.

abstract class User {
  constructor(
      private firstName: string,
      private lastName: string,
      private nickname: string
  ){}
  abstract getNickName(): void
  getFullName() {
     return ${this.firstName} ${this.lastName}
  }
}

class Player extends User{
   getNickName() {
     console.log(this.nickname)
   }
}

const nico = new Player("nico","las","L\N");

private, protected

private

해당 키워드로 property나 method를 선언하면

클래스의 인스턴스와 자식클래스에선 접근 할 수 없다.

protected

마찬가지로, 클래스의 인스턴스에서는 접근 할 수 없으나

자식클래스에선 접근 할 수 있다.

type Words = {
	[key: string]: string // key값을 접근할 때 string 타입도 허용
}
class Dict{
  private words: Words
  constructor() {
    this.words={}
  }
  add(word: Word){ // Word 클래스를 매개변수로 받는다 
    if (this.words[word.term] === undefined) {
   		this.words[word.term] = word.def;
    }
  }
  def(term: string){
    return this.words[term]
  }
}

class Word{
    constructor(
        public term:string,
        public def:string
    ){}
}
const kimchi=new Word("kimchi","한국의 음식");
const dict=new Dict()
dict.add(kimchi)
dict.def("kimchi") // "한국의 음식"

abstract method

  • abstract 클래스 안에서만 abstract method를 선언 할 수 있다.

  • abstract method는 call signature 앞에 abstract 키워드를 붙여 선언한다.

  • abstract 클래스를 상속 받는 클래스들은 abstract method를 구현해야 한다.

abstract class 일때

 abstract class User{
     constructor(
         protected firstName:string,
         protected lastName:string
     ){}
     abstract sayHi(name:string):string
     abstract fullName():string
 }
 class Player extends User{
     fullName(){
         return`${this.firstName}${this.lastName}`
    }
     sayHi(name:string){
         return'Hello ${name}'
    }
 }

interface로 바꾸고 난 후

// `interface`는 `private`, `protected` 접근제어자를 사용할 수 없다.
// 따라서, interface를 implements하는 클래스에서 constructor에서 public으로 property를 선언 해주어야 한다.
// 하지만, js로 컴파일시 `interface`문이 사라지므로 
// 번들 용량이 줄어드는 이점이 있다.
 interface User{
     firstName: string,
     lastName: string,
     sayHi: (name:string): string,
     fullName: (): string
 }
 interface Human{
 	race: white 
 }
 class Player implements User, Human{
 	constructor() {
      public firstName: string,
      public lastName: string,
      public race: string
    } 
   	fullName(){
   		return`${this.firstName}${this.lastName}`
   	}
   	sayHi(name:string){
   		return'Hello ${name}'
   	}
 }

type ? interface ? 뭘 쓰지

공식 문서에서도 나오는 내용이지만, objectclass의 타입을 정의할 때엔 interface를 나머지는 type을 사용하는게 권장 된다.

tsconfig.json

{
  "include": ["src"], // 읽어올 파일들의 경로 
  "compilerOptions": {
    "outDir": "build", // 컴파일시 저장되는 경로
    "target": "ES6", // 컴파일후 적용되는 자바스크립트 문법의 ver.
    "lib": ["ES6"],  // 타입 정의가 내장된 라이브러리 ex) DOM, WebWorker
    "strict": true, // strict mode 
    "esModuleInterop": true, // 모듈 import 할때 범용적으로 쓰임, babel과의 호환성을 위해서도
      // https://it-eldorado.tistory.com/128 자세한 내용 참고 
    "module": "CommonJS" //  Node.js 환경에서 실행되는 모듈 시스템 방식
  }
}

.d.ts

컴포넌트 혹은 모듈의 타입을 정의 해주는 파일이다.

myPackage.js

export function init(config) {
  return true;
}
export function exit(code) {
  return code + 1;
}

myPackage.d.ts

interface Config {
url: string;
}

declare module "myPackage" {
function init(config: Config): boolean;
function exit(code: Number): Number;
}

# JSDOC

자바스크립트 모듈의 타입을 타입스크립트로 정의하지 않고

주석(?)을 제공하여 타입스크립트에게 타입힌트를 제공하는 API 문서 생성기이다

아래의 코드에서는 각각의 함수에 대한 call signatures를 정의 해주었다

## 작성순서
> 1. tsconfig.json

`"allowJs": true` 추가 

> 2. 타입을 정의해줘야 하는 js 파일

// @ts-check
/** 작성후 enter (자동완성)


```ts
// @ts-check
/**
 * Initializes the project
 * @param {object} config
 * @param {boolean} config.debug
 * @param {string} config.url
 * @returns boolean
 */
export function init(config) {
  return true;
}

/**
 * Exits the program
 * @param {number} code
 * @returns number
 */
export function exit(code) {
  return code + 1;
}

DefinitelyTyped

type 정의를 위한 레포지터리

https://github.com/DefinitelyTyped/DefinitelyTyped

                               

0개의 댓글