[TypeScript] 타입추론, 타입단언

황수콩·2023년 11월 28일
0
post-thumbnail

🕵🏻‍♂️ 타입 추론

👀 타입 추론이란

타입스크립트가 코드를 해석해 나가는 동작을 의미

👓 변수 추론

할당값을 기준으로 추론

let x = 3; //number로 추론
let isValid = true; //boolean으로 추론
let names = “수빈”; //string으로 추론

↪️ 함수 반환 타입 추론

return문을 기준으로 추론

반환값이 따로 없으면 void로 추론

function printHello() { //string으로 추론
  return "Hello!";
}

function isTrue() { //boolean으로 추론
  if(1+2 == 3) return true;
  else return false;
}

🧚🏻‍♀️ 함수 파라미터 타입 추론

파라미터의 기본값을 기준으로 타입을 추론

function addNum(x=10, y=3) { //x,y,addNum은 모두 number로 추론된다.
  return x+y;
}

function isOdd(x=10, y=3) { //x,y는 number로 isOdd는 boolean으로 추론
  if(x+y % 2 == 0) return false;
  else return true;
}

🗃️ 인터페이스 타입 추론

(상속에 관한 인터페이스 타입 추론)

class 부모클래스 {
	String 부모필드;
}

class 자식클래스 extends 부모클래스 {
	String 자식필드;
}

부모클래스 변수 = new 자식클래스(); // 부모클래스 타입 변수이지만, 자식클래스는 부모클래스를 상속(포함)하기에, 생성까지는 문제 없음
변수.부모필드; // 사용하는데 문제없음
변수.자식필드; // ERROR - 하지만 할당된 변수는 부모클래스 타입이기 때문에 자식클래스에만 있는 필드를 접근할 경우 에러가 뜨게 된다.

부모 클래스를 상속한 자식 클래스를 new 생성자로 생성할때

변수의 타입을 부모 클래스로 지정해 생성할 수 있다는 원리에서 따온 개념!

interface TSgirls {
   name: string;
   age: number;
}
interface YB extends TSgirls {
   doSopkathon: boolean;
}
interface OB extends TSgirls {
  didAppjam: boolean;
}

const p1: TSgirls = { name: 'hyein', age: 24 };
const p2: YB = { name: "subin", age: 22, doSopkathon: true };
const p3: OB = { name: "hyein", age: 24, didAppjam: true };

const arr1 = [p1, p2, p3]; // const arr1: TSgirls[]

const arr2 = [p2, p3]; // const arr2: (YB | OB)[]

👀 arr1 과 arr2 의 타입은 어떻게 추론 될까?

바로 다른 타입으로 할당 가능한 타입은 제거가 되는데, YB와 OB 인터페이스는 둘다 TSgirls에 할당이 가능하기 때문에 ➡️  arr1 변수의 타입은 둘다 제거가 되고 TSgirls 타입만 남게 된다
arr2YBOB 타입의 변수를 받는데, 이 둘은 서로 상속되는 관계가 아니기 때문에 별개의 타입으로 취급된다. ➡️ 따라서 두개의 타입을 묶는 유니온 타입으로 추론이 된다

🚛 제네릭 타입 추론

함수를 호출할 때 전달되는 값으로부터 타입을 추론

function sayHello<T>(arg: T): T {
    return arg;
}

// 제네릭 타입을 명시적으로 지정하지 않아도, 타입스크립트가 추론하여 타입을 결정
let result = sayHello("Hello, TypeScript!");

✋🏻 타입 단언

👀 타입 단언이란?

개발자가 해당 타입에 대해 확신이 있을 때 사용하는 타입 지정 방식

✍🏻 적용 방법

const name: string = 'subin';

1️⃣ as 키워드를 이용

const name = 'subin' as string;

2️⃣ <타입> 을 변수에 부여

const name = <string>'subin'

이 둘 중에서는 as 키워드를 더 많이 사용한다 ( 두 번째 경우는 HTML 태그 등과 혼동될 수 있기 때문! )

😡 사용을 지양해야하는 이유

👩🏻‍💻 "다음의 값은 이런 타입을 가진거야 그러니까 에러를 띄우지마!”

타입 단언은 타입 선언 혹은 타입을 변환하는 Type Casting과는 달리, 실제 데이터 타입을 변경하지 않고 에러만 방지하는 기능을 합니다!

타입 단언은 타입 에러를 없애줄 뿐 런타임 에러를 막아주지 않는다

💡 즉, 컴파일 타입에 잡을 수 있는 에러를 없앰으로서 원래대로면 생기지 않았을 런타임 에러를 발생시킬 수 있다.

interface human {
	sayhi: string;
  	age: number;
}

let person = {
	// 아무것도 안 넣음
} as human;

console.log(person.sayhi)

👀 무슨 일이 일어날까!!

당연히 에러가 발생!! ➡️ 하지만 런타임에 에러가 날 것이다.

타입 단언을 사용했기 때문에 오류가 난 코드를 컴파일 단계에서 발견하지 못하고 런타임 단계까지 가서야 발견하게하였다. ▶️ 이는 타입스크립트를 사용하는 큰 장점을 무시한 셈!!!!

💣 any 타입 단언

값을 any 타입으로 단언하게 되면 특정 값에 대한 타입 검사를 사실상 완전히 무효화할 수 있다.

(3 as any).substr(0, 3);

위 코드는 실제로 실행한다면 런타임 에러가 발생하지만, 타입 검사는 통과한다.

번거로운 타입 검사를 피할 수 있지만, any를 사용한 타입 단언은 어쩔 수 없는 경우를 제외하곤 피하는 것이 좋다. ➡️ any를 사용한 타입 단언은 타입스크립트를 사용하는 근본적인 이유에 정확히 반하기 때문이다.

⏱️ 언제 사용 할까?

🌐 HTML요소에 접근할 때

우리는 calculateButton이 적확히 HTMLButtonElement 일 수 밖에 없다는 것을 알고있다

이럴 때 타입 단언 을 사용한다

🙅🏻 null 아님 단언

  • !를 이용하여 그 값이 null이 아니라는 단언한다.
  • 타입 체커는 알지 못하지만, 값이 null이 아니라고 확신할 수 있을 때 사용

⌨️ JSON 값을 parsing 해서 사용하는 경우

JSON.parse를 거치고 난 값은 any 타입이다

파싱한 후에 타입을 갖게하기 위해서 타입 단언 을 사용한다

profile
@binllionaire

0개의 댓글