[TypeScript] 타입스크립트 알아보기

김서현·2023년 3월 10일
0

TypeScript 스터디

목록 보기
1/4
post-thumbnail

먼저, 타입스크립트가 다른 언어들과 다른점은?

  • 파이썬, 루비 : 인터프리터로 실행됨
  • 자바, C : 저수준 언어로 컴파일됨
  • 타입스크립트는 또 다른 고수준 언어인 JS로 컴파일 되고, JS로 실행되는 언어

📌 TypeScript와 JavaScript의 관계

TypeScript는 JavaScript의 '상위집합'

  • .js 파일에 있는 코드는 이미 TS라고 할 수 있다!
  • 반대로, TS는 별도의 문법이 있기 때문에 일반적으로 유효한 JS가 아니다.

타입 추론 : 타입 체커로 잠재적 문제점 찾아내기.

  • TS는 JS 런타임 동작을 모델링하는 타입 시스템을 가지고 있음.
  • Typescript의 목표 : 런타임에 오류를 발생시킬 코드를 미리 찾아내는 것. (❗ 그러나 모든 오류를 잡아내는 것은 아님)
  • 오류 뿐만 아니라 의도와 다른 코드도 찾아낼 수 있다.
    👉 interface를 이용해서 의도를 명시하기
  interface State { //interface를 통해 "의도"를 명시
    name: string;
    capital: string;
  }
  const states3: State[] = [
    { name: "Alabma", capitol: "Montgomery" }, //error: 'State'형식에 'capitol'이(가) 없습니다. 'capital'을 쓰려고 했습니까?
    { name: "Alabma", capitol: "Montgomery" },
    { name: "Alabma", capitol: "Montgomery" },
  ];
  for (const state of states3) {
    console.log(state.capital); 
  }

📌 타입스크립트 설정 이해하기

tsconfig.json 설정하기

  • noImplicitAny :변수들에게 미리 정의된 타입을 주지 않으면 오류가 나도록 하는 설정
  • strict NullChecks : null과 undefined가 모든 타입에서 허용되는지 확인하는 설정
    👉 설정하지 않는다면 런타임 오류로 "undefined는 객체가 아닙니다"라는 오류를 맞이할 수 있으므로 설정하는 것이 좋음.
const x: number = null; // 해제되었을 때 : 정상
const x: number = null; // 설정했을 때 : 'null' 형식은 'number'형식에 할당할 수 없습니다.

✅ 결론 : 웬만한 상황에서 두 가지 다 설정하자 !


📌 코드 생성과 타입이 관계없음을 이해하기

타입스크립트 컴파일러가 하는 역할

  • 컴파일 : 최신 TS,JS를 브라우저에서 동작할 수 있도록 구버전 JS로 transpile
  • 타입 체크 : 코드의 타입 오류 체크
    ❗ 그런데 이 두가지는 완벽히 독립적으로 동작한다!

    👉 TS가 JS로 변환될 때, JS 실행 시점에 타입은 영향을 미치지 않는다.
    👉 타입 체크는 TS에서 컴파일 이전에 가능성이 있는 오류를 체크하지만, JS로 컴파일될 때 타입은 모두 사라지기 때문.
    👉 TS error로 지정되어도 JS로 컴파일은 될 수 있다!

    ➕ TS error가 있을 때 컴파일되지 않게 설정하려면 tsconfig.jsonnoEmitOnError를 설정

런타임에는 타입 체크가 불가능

실제로 JS로 컴파일되는 과정에서 모든 인터페이스, 타입, 타입 구문은 그냥 제거되어 버리기 때문
👉 그렇다면 런타임에 타입 정보를 유지하는 방법은?

  1. 직접 속성이 존재하는지 체크하기
if('height' in Shape) {
// ...
}
  1. 태그된 유니온 사용하기 📝
    명시적으로 타입을 저장해서 확인하기
interface Square2 {
  kind: "square"; //태그
  width: number;
}

interface Rectangle {
  kind: "rectangle"; //태그
  width: number;
  height: number;
}

type Shape2 = Square2 | Rectangle; //태그된 유니온

function calculateArea2(shape: Shape2) {
  if (shape.kind === "rectangle") { // 태그를 이용하여 분기 처리
    return shape.width * shape.height;
  } else {
    return shape.width * shape.width;
  }
}
  1. 타입을 클래스로 만들기
  • TS에서 클래스도 타입으로 쓸 수 있다.
  • 상황에 따라 타입으로, 값으로 사용 가능.
  • 클래스는 JS 컴파일 과정에도 제거되지 않기 때문에 타입 정보를 유지할 수 있는 것.

타입 연산은 런타임에 영향을 주지 않는다.

타입 연산도 마찬가지로 컴파일 시 제거되므로 값을 정제해야 하는 경우 JS 연산을 통해 변환을 수행해야 한다.

function asNumber(val: number | string) : number {
  return val as number; //타입 연산
}

🔽🔽🔽 ✅ 이런 코드를 지향하자!

function asNumber(val: number | string) : number {
  return typeof(val) === 'string' ? Number(val) : val;

TS 타입으로 함수 오버로드는 불가능

런타임에 타입이 모두 제거되는 것을 고려했을 때 함수 오버로딩은 불가능하다. 온전히 타입 수준에서만 여러 개의 선언문 작성이 가능하지만, 구현체는 오직 하나 뿐

function add(a: number, b: number) { // error: 중복된 함수 구현입니다.
  return a + b;
}
function add(a: string, b: string) { // error: 중복된 함수 구현입니다.
  return a + b;
}


📌 구조적 타이핑에 익숙해지기

  • 자바스크립트는 본질적으로 덕 타이핑 기반.

    덕 타이핑이란?
    객체가 어떤 타입에 부합하는 변수와 메서드를 가질 경우 객체를 해당 타입에 속하는 것으로 간주하는 방식

구조적 타이핑 예시

  • 아래 NamedVector 구조가 Vector2D와 호환되기 때문에 caculateLength 호출이 가능하다! --> 타입이 열려있다.
interface Vector2D {
  x: number;
  y: number;
}

function calculateLength(v: Vector2D) {
  return Math.sqrt(v.x + v.y);
}

interface NamedVector {
  name: string;
  x: number;
  y: number;
}

const v: NamedVector = { x: 3, y: 4, name: "Zee" };
calculateLength(v);
  • 이런 점을 주의하자.
interface Vector3D {
  x: number;
  y: number;
  z: number;
}

const vec3D = {x:3, y:4, z:1, address:'123 Broadway'}

function calculateLengthL1(v:Vector3D) {
  let length = 0;
  for (const axis of Object.keys(v)) {
    const coord = v[axis]; // 구조적 타이핑에 의해 추가된 속성으로 위 vec3D처럼 axis에 string이 들어올 수도 있는 것..!
    length += Math.abs(coord);
  }
return length;
}

🔽🔽🔽 ✅ 결론 : 루프보다는 모든 속성을 각각 더하는 구현이 낫다.

function calculateLengthL1(v: Vector3D) {
return Math.abs(v.x) + Math.abs(v.y) + Math.abs(v.z);
}

마지막으로,
❗ any 타입은 타입 체커와 타입스크립트 언어 서비스를 무력화시켜버리므로 최대한 지양하자!

5개의 댓글

구조적 타이핑 신기하네요!! 그동안 타입스크립트는 타입을 엄밀하게 지정한다는 생각을 하고 있었는데, 저렇게 호환이 될 수도 있고, 이 경우 map 을 돌렸을 때 원하지 않는 결과가 나올 수도 있다는 사실이 너무 흥미로워요!! 잘 봤습니다 :)

2개의 답글
comment-user-thumbnail
2023년 3월 12일

컴파일할 때 타입이 다 제거된다는 걸 기억하고 있어야 에러를 방지하고 불필요하게 낭비되는 코드를 막을 수 있겠네요! 뭔가 코드를 작성할 때 타입에 되게 의지하는 (?) 그런 느낌인데 경각심을 좀 가져야겠어요! 좋은 글 감사합니다:)

답글 달기
comment-user-thumbnail
2023년 3월 19일

헉 세상에 사실 타입스크립트를 쓰면서도 이게 맞나 계속 고민하고 그냥 얼레벌레 써왔었는데… 이렇게 잘 정리해주셔서 감사합니다!!! 많은 도움이 됐어요!

답글 달기