Today I Learned_230223

4 분 소요

TypeScript

인프런 타입스크립트 강의 수강

interface A {
    talk: () => void;
}
const a : A = {
    talk() {return 3;}
}
const b = a.talk(); //이 경우 b의 타입은 3이 아니라 void가 된다.
//void면 원칙적으로 리턴값이 없어야 하는 것이 맞다.

const c = a.talk() as number; //강제로 바꿔줘야 하는데 항상 바꿀 수는 없다. 이거로는 불충분
const d = a.talk() as unknown as number; //이렇게 해야지 바꿀 수 있다.
const e = <number><unknown>a.talk();

//앞에 꺽쇠보다는 as가 더 권장됨
//react의 jsx에 태그들이 쓰이는데, <>때문에 타입스크립트가 헷갈려서 잘 쓰기 힘들다.
//꺽쇠보다는 as를 써보자.
  • unknown과 any의 차이점
    • 우선 unknown 많이 사용한다.
    • any는 타입 검사를 포기해버린다. 나 타입검사 안 할거라는 포기 선언
    • unknown은 지금 당장은 타입을 정확하게 모를 때 사용. 지금은 잘 모르겠고 나중에 쓸 때 정의해서 쓰겠다. 포기와는 다르다.
  • unknown은 타입을 정해줘야 한다.
  • try catch의 error는 unknown이 되어야 한다.
    • error는 어떤게 나올지 모름
    • 원래는 any였다가 error로 바뀜
interface A {
    talk:() => void;
}
const a : A = {
    talk() {return 3;}
}
const b : any = a.talk();
b.method(); //.method()는 존재하지 않는데 여기서 오류라고 생각하지 않는다.

const b : unknown = a.talk();
b.method(); //unknown으로 하면 오류남

const b : unknown = a.talk();
(b as A).talk();  //unknown은 나중에 타입을 지정해서 사용
  • 타입간 대입 가능 표 (파란색 표시랑 초록색은 다름)
  • 초록색 : strict true. 그냥 X라고 생각하자.
    • any는 void에 대입할 수 있다.
    • null은 void에 대입할 수 없다.
  • 넣었는데 any나 never가 나왔다면 의심해보자..

https://user-images.githubusercontent.com/10962668/179646513-3c3be896-3bbc-4784-848b-06bc47e8b129.png

  • 타입 가드(타입 좁히기)
  • unknown일 때 빼고는 가급적이면 as 하지 말자.
    • 남이 만든 타입이 틀렸을 때 as 쓰기..
  • 타입스크립트는 if문 통해서 타입 구분할 수 있음
  • 객체들간의 타입 검사를 할 때는 객체들간의 차이를 찾아야 한다.
  • 리턴값에 is가 있는 것들은 커스텀 타입 가드 함수
    • 커스텀 타입 가드는 if문 안에 사용해서 타입스크팁트에게 정확한 타입이 무엇인지 알려주는 것
    • 타입 판별 함수는 직접 만들어야 한다.
    • is가 아니면 타입 추론이 안 되는 경우도 있다.
function numOrStr(a: number | string) {
  if (typeof a === 'string') {
    a.split(',');  
  } else {
    a.toFixed(1);
  }
}
// 아래와 같이 했을 때 오류남(매개변수로 숫자만 줬을 때
function numOrStr(a: number | string) {
    a.toFixed(1); //a가 string일 가능성도 있기때문에
}
//a임을 분명히 하려면 아래와 같이 하면 됨 - 근데 안된다
function numOrStr(a: number | string) {
    (a as number).toFixed(1);
}
numOrStr('123') //이거 넣었을때 오류남 (자바스크립트 단에서 에러)

//if문 안에서 숫자인게 확실해진다.
function numOrStr(a: number | string) {
    if (typeof a === 'number')
        a.toFixed(1);
    if(typeof a === 'boolean')
        a.toString(); //파라미터로 boolean을 받고 있지 않기 때문에 a는 never가 됨
}

//else까지는 확인해준다.
//타입스크립트는 배열도 확인해 준다.
//또는 타입일 때는 타입을 잘 체크해 본다.
function numOrNumArr(a: number | number[]) {
  if (Array.isArray(a)) { //number[]
    a.slice(1);  
  } else {
    a.toFixed(1); //number
  }
}

//같은 속성인데 값이 다르거나('type')
//아예 속성 이름 자체가 다름
type B = { type: 'b', bbb: string }; //객체를 만들 때 type이라는 속성을 만드는 습관을 들이자(라벨/태그 느낌)
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 typeCheck(a: A) {
    if ('bbb' in a) { //a 객체 안에 bbb라는 속성이 있다
        a.bbb;
    } else if ('ccc' in a) {
        a.ccc;
    } else {
        a.ddd;
    }
}
//보통은 값으로 구분하는 방법을 선호함

interface Cat { meow: number }
interface Dog { bow: number }
function catOrDog(a: Cat | Dog): a is Dog { //return값에다가 is를 쓸 수 있음. 강아지이면 true 리턴
    //타입 판별 직접 만들기
    if ((a as Cat).meow) { return false }
    return true;
}

//자바스크립트 문법 활용해서 타입 구분도 가능하지만
//타입을 구분해주는 커스텀 함수를 직접 만들 수 있다.
const cat: Cat | Dog = { meow: 3 }
if (catOrDog(cat)) { // 커스텀한 타입 가드
    console.log(cat.meow);
}
if ('meow' in cat) { //자바스크립트 문법 활용한 타입 가능
    console.log(cat.meow);
}

//타입스크립트 버전에 따라서 에러가 계속 달라진다.
//"target": "es2022","lib": ["es2020"],"module": "ES2022",
const isRejected = (input: PromiseSettledResult<unknown>): input is PromiseRejectedResult => input.status === 'rejected';
const isFulfilled = <T>(input: PromiseSettledResult<T>): input is PromiseFulfilledResult<T> => input.status === 'fulfilled';

const promises = await Promise.allSettled([Promise.resolve('a'), Promise.resolve('b')]);
const errors = promises.filter(isRejected);

//자바스크립트에서 에러 필터링 하려면 아래와 같이 하면 됨 
const errors = promises.filter((promise) => promise.status === 'rejected')
  • Promise는 실행하고 나면 Pending상태(비동기 실행 상태)가 되고 그 다음 Settled상태(완료지 성공인지 실실패인지 모름)가 된다.
  • Settled에는 Fulfilled(성공), Rejected(실패)가 있다.
  • 성공 여부와 상관 없이 Settled가 됨
  • promises.then().catch()
    • then : Fulfilled
    • catch : rejected
    • 둘 다 합친거 : settled
  • 커스텀 타입 가드를 사용하면 정확한 타입을 사용할 수 있고 Promise에서 잘 필터링 할 수 있게 된다.

  • class인 경우 instanceof 연산자도 가능!
  • class는 instanceof 연산자를 통해 타입을 구분한다.
class A {
    aaa() {}
}
class B {
    bbb() {}
}
//클래스 이름 자체가 타입 자리에 올 수 있다.
//클래스 자체를 의미하는 것이 아니라 new A한 애들(인스턴스)을 의미
function aOrB(param: A | B) {
    if(param instanceof A) {
        param.aaa();
    }
}

aOrB(A) //이거 안된다

빈 객체 타입{}과 Object

  • 모양이 객체 같지만 모든 타입이라고 생각하자
    • null과 undefined는 제외
  • 겉보기에는 객체라 착각하기 쉬움
  • 실제 객체는 소문자인 object에 해당
  • 하지만 실제 객체를 만들 때는 object를 지양하고 interface, type, class를 사용하도록 하자.
  • tsc 4.8부터는 아래 공식이 성립
    • unknown = {} |null | undefined
    • unknown은 모든 타입, null, undefined가 합쳐진 것이다
    • unknown을 if 안에 넣으면 {}이 된다.
const x : {} = 'hello';
const y : Object = 'hi';
const xx : object = 'hi'; //객체 안에 string 넣는거 안 됨
const yy : object = {hello : 'world'};
const z : unknown = 'hi';

if(z) {
    z; //z는 {}타입이 된다.
}

카테고리:

업데이트: