타입스크립트 공부 (1)

최자은·2023년 6월 28일
0

타입스크립트

목록 보기
2/5
  • 컴파일러의 역할
    • 타입 검사
    • 코드 변환
    • 실제 프로젝트에서 타입 검사를 자동으로 안해줌
      => 직접 코드를 입력해서 타입 검사를 해야함.
      => tsc --noEmit (단순 타입 검사)
      => vscode나 웹스톰이 반드시 필요
  • ts.config 파일
    • strict, esModuleInterop은 항상 "true"로 해놓는 것이 좋다.
      • strict: "true"를 하지 않으면 타입스크립트 쓰는 의미가 줄어듬 !
    • forceConsistentCasingInFileNames: "true"
      • 파일을 불러올 때, 윈도우의 경우 대소문자 구별을 잘 안함. 반면, 리눅스나 맥에서는 대소문자 구별을 안하면 파일을 못 찾음. 그래서 이런 경우에서 발생하는 실수를 방지하기 위해 대소문자 구분을 확실히 해서 파일을 불러올 수 있도록 하는 옵션
    • skipLibCheck: "true"
      • 라이브러리 체킹을 건너띄라는 것.
      • 프로젝트를 진행하다보면 여러 라이브러리를 설치해서 사용하게 되는데, 각 패키지의 타입을 정리해놓은 d.ts 라는 파일이 있다. 그런데, 이 수 많은 파일들을 모두 체크하려면 컴파일러가 느려지기 때문에, 실제로 쓰는 타입만 검사하도록 하는 옵션.
  • 타입스크립트
    자바스크립트의 변수, 매개변수, 리턴 값에 타입을 붙이는 것.
    • 타입 추론 적극 활용하기
    • 타입은 최대한 좁게 적용하기
  • 타입 선언
    • interface, type, Array<>, 그리고 변수에 바로 선언해주기
// 아래의 경우 
function Add(x:number, y:number): number // 타입 
function Add(x, y) { // 실제 코드
	return x + y
}
  • 주의
    • 빈 배열을 조심하기 !
      빈 배열을 선언한 경우, 타입이 never가 될 수 있는데, 이렇게 되면 어떠한 타입도 올 수가 없다.
      const arr = [] // arr: never
      arr[0]
      => 빈 배열을 주는 경우 타입을 미리 지정해주자
  • Enum
    변수들을 하나의 그룹으로 묶고 싶을 때 주로 사용
const enum Edirection {
  Up, // UP = 'hello' | 2 | true 등 직접 지정해줄 수 있음
  Down,
  Left,
  Right,
}

const a = Edirection.Up; // 0
const b = Edirection.Down; // 1
const c = Edirection.Right; // 3
  • as const
    타입스크립트가 타입 추론을 엉뚱하게 하면 직접 제대로 선언해줘야함
    지정해준 값을 그대로 사용하겠다 하는 경우 'as const'를 쓸 수 있음.
// 타입 추론이 제대로 안된 경우
const Edirection = {
  Up = 1, 
  Down = 2,
  Left = 3,
  Right = 4,
} 
// const Edirection: {
//    Up: number;
//    Down: number;
//    Left: number;
//    Right: number;
// }

// 2. 타입 지정 제대로 해주는 간단한 방법 as const
const Edirection = {
  Up = 1, 
  Down = 2,
  Left = 3,
  Right = 4,
} as const;
// const Edirection: {
//    readonly Up: 1;
//    readonly Down: 2;
//    readonly Left: 3;
//    readonly Right: 4;
// }
  • keyof
// 1. key 타입만 가져오고 싶을 때
const obj = { a: 12, b: "world", c: true };
type key = keyof typeof obj;

// 2. value 타입만 가져오고 싶을 때
const obj = { a: 12, b: "world", c: true } as const;
type key = (typeof obj)[keyof typeof obj];
  • type vs interface
    간단한건 type, 객체지향을 하고 싶을 땐 interface
    • type
      같은 이름으로 여러 번 선언할 수 없음.(에러 발생)
      type Animal = { breath: true };
      type A = Animal & { breed: true };
      type H = A & { think: true };
      const je: H = { breath: true, breed: true, think: true };
    • interface
      같은 이름으로 여러 번 선언할 수 있다. 선언할 때 마다 자동으로 합쳐짐
type Animal = { breath: true };
type A = Animal & { breed: true };
type H = A & { think: true };

interface B extends A {
  breed: true;
}

const b: B = { breath: true, breed: true };
  • type / interface 공통점
    • 상속된다
  • union
    여러 개 중 하나만 있어도 된다.
// 아래 경우 타입추론으로 결과값이 string | number가 되서 둘 중 하나가 왔을 때 문제가 발생할 수 있으므로 아래와 같이 사용하는 것은 지양
function add(x: string | number, y: string | number): string | number {
  return x + y;
}

type A = { hello: "world" } | { type: "script" };
const a: A = { hello: "world" };
  • intersection
    모든 속성이 다 있어야 한다.
type A = { hello: "world" } & { type: "script" };
const a: A = { hello: "world", type: "script" };
  • 타입을 집합으로 생각하자 (좁은 타입, 넓은 타입)
    좁은 타입 - 더 구체적인 타입
type A = { name: string };
type B = { age: number };

type AB = A | B;

type C = A & B;

// 1. 넓은 타입을 좁은 타입에 대입
const ab: AB = { name: "hello" };
// 2. 좁은 타입을 넓은 타입에 대입(잉여 속성 검사로 에러 발생)
const c: C = { name: "hello", age: 22, married: false };
// 3. 좁은 타입을 넓은 타입에 대입(잉여 속성 검사를 피해서 선언해주면 에러 발생 안함)
const obj = { name: "hello", age: 22, married: false };
const d: C = obj;
  • 잉여 속성 검사
    타입스크립트에서는 객체 리터럴을 바로 대입할 때는 잉여 속성 검사라는 추가 기능이 들어간다.
  • void
    리턴 값을 넣으면 안됨. 리턴값 없음
    매개변수와 메서드를 void로 선언해주고 리턴값을 실제 어떠한 값으로 주는건 가능
    • 매개변수와 메서드의 void 의미 : 리턴 값을 사용하지 않겠다, 리턴 값이 뭐든 상관 안함
    • function a():void 의미: 리턴값이 없다.
function a(): void {
  return undefined; // null, string, number 들은 안됨
  // return ;
}

a();

// 매개변수
function a(callback: () => void): void {
  return;
}

a(() => {
  return "3";
}); // 에러 x

interface Human {
  //   talk: () => void; 에러 x
}

const human: Human = {
  // 메서드
  talk() {
    return "abd"; // 에러 x
  },
};
  • unknown vs any
    • any : 타입스크립트가 타입 체킹을 포기한다.
    • unknown : 이후에 타입을 직접 정해줘야함.
      • 지금 당장 타입을 정확하게 모를 때 씀
interface A {
  talk: () => void;
}

const a: A = {
  talk() {
    return 3;
  },
};

// 1
const b: unknown = a.talk();
(b as A).talk(); // 직접 지정

// 2
try {
} catch (error) {
    // error의 타입이 unknown이라고 나옴
    (error as Error).message
}
  • 타입 가드 (타입 좁히기 기법)
    원시값일 때는 typeof, 배열일 때는 Array.isArray()
// 1. 원시값
function numOrStr(a: number | string) {
  // 에러 발생, number 일수도 string 일수도 있기 때문
  a.toFixed(1);
  // 에러 발생 안함. 그러나 나의 실수가 있을 수 있기 때문에 as 쓰면 안됨.
  (a as number).toFixed(1);
  // 타입 가드. 에러 발생 안함
  if (typeof a === "string") {
    a.split(",");
  }
  if (typeof a === "number") {
    a.toFixed(3);
  }
}

numOrStr("123");
numOrStr(3);

// 2. 배열값
function numOrNumArray(a: number | number[]) {
  // a가 array 인지 구분
  if (Array.isArray(a)) {
    // number[]
    a.concat(4);
  } else {
    //number
    a.toFixed(5);
  }
}

numOrNumArray([1, 2, 3]);
numOrNumArray(3);

// 3. class
class A {
  aaa();
}

class B {
  bbb();
}

// 클래스는 그 자체로 타입이 될 수 있음.
// 대신 클래스 자체를 의미하는 것이 아니고 인스턴스를 의미함. (class 간에는 instanceof 로 구분한다.)
// 클래스 자체의 타입은 typeof 클래스(typeof A)
function aOrB(param: A | B) {
  if (param instanceof A) {
    param.aaa();
  }
  if (param instanceof B) {
    param.bbb();
  }
}

aOrB(new A());
aOrB(new B());

// 4. 객체 간 타입 구별
type B = { type: "b"; bbb: string };
type C = { type: "c"; ccc: string };
type D = { type: "d"; ddd: string };
type A = B | C | D;

function typeCheck(a: A) { // 값으로 구분
  if (a.type === "b") {
    a.bbb;
  } else if (a.type === "c") {
    a.ccc;
  } else {
    a.ddd;
  }
}

function typeCheck2(a: A) { // 속성으로 구분
  if ("bbb" in a) {
    a.type;
  } else if ("ccc" in a) {
    a.type;
  } else {
    a.type;
  }
}
  • 커스텀 타입 가드
    타입을 판별을 직접 만들고, 타입을 구분해주는 커스텀 함수를 직접 만들 수 있다.
interface Cat {
  meow: number;
}
interface Dog {
  bow: number;
}

// is
// 타입을 구분해주는 커스텀 함수를 본인이 직접 만들 수 있음.
function carOrDog(a: Cat | Dog): a is Dog {
  // 타입 판별 직접 생성
  if ((a as Cat).meow) {
    return false;
  }
  return true;
}

function pet(a: Cat | Dog) {
  if (carOrDog(a)) {
    console.log(a.bow);
  }
  if ("meow" in a) {
    console.log(a.meow);
  }
}
profile
모든 과정을 기록하며 꾸준히 성장하고 실수를 반복하지 말자 !

0개의 댓글