[Typescript] 타스형! 스터디 2주차

woo·2022년 10월 29일
0

Typescript

목록 보기
2/13
post-thumbnail

➕ zerocho님 typescript all-in-one 강의를 듣고 정리한 내용입니다.

✔ 섹션1

type과 intersection

// interface끼리는 서로 합쳐짐
interface A { a: string }
interface A { b: string }
const obj1: A = { a: 'hello', b: 'world' }

// Type Alias끼리는 서로 합쳐지지 않고 에러남
type B = { a: string }
type B = { b: string }
const obj2: B = { a: 'hello', b: 'world' } // error

Type Alias는 intersection으로 상속, interface는 extends로 상속

객체 리터럴

객체 리터럴은 잉여 속성 검사가 있음.

중간에 다른 변수를 하나 껴서 넣으면 에러가 나지 않음

따라서 ts에서 객체 리터럴을 바로 대입하려면 잉여속성검사를 해야한다!

type A = { hello: string };
const a: A = { hello: 'world', why: 'error' }; // why가 없다고 error

const b = { hello: 'world', why: 'error' }; // 잉여 속성 검사
const c: A = b;

void의 두가지 사용법


a와 b의 리턴값이 모두 void

return 값이 void로 function을 선언한 것(return 값 없음)과 메소드로 선언한 void, 매개변수로 선언한 void(return 값 존재가능)는 다르다

전자는 return값이 없다 후자는 return값을 사용하지 않겠다를 의미한다. 하지만 후자에 경우 return type을 void로 받기에 a.talk의 return 값이 3임에도 type을 void로 인식하는 문제가 발생한다! (이럴 경우 number로 다시 강제 타입 변환 as unknown as number )

function hello() : void{ // 함수 return값 void
}

interface A {
    talk: () => void;  // 메서드 void
}
const a: A = {
    talk() { return 3; }
}

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

declare을 붙이면 type만 지정할 수 있음( 구현은 다른 파일에 있어야함 ) , js변환시 사라짐

매개변수 함수에서 void와 undefiend 차이

declare function forEach<T>(arr: T[], callback: (el: T) => undefined): void;
let target: number[] = [];
forEach([1, 2, 3], el => target.push(el));

![](https://velog.velcdn.com/images/soy0830/post/aec7805f-f400-4e57-afe2-9a2aa0c297f4/image.png)
//push는 return 값이 number여서 undefined 하면 error
declare function forEach<T>(arr: T[], callback: (el: T) => void): void;
let target: number[] = [];
forEach([1, 2, 3], el => target.push(el)); // return type number
forEach([1, 2, 3], el => {target.push(el)}); // return type void
// push return값 number인데 void해도 error 안나는 이유는 매개변수에서 void는 실제 return값이 무엇이든 상관하지 않아서

unknown과 any(그리고 타입 대입가능표)

any : 타입검사 안할꺼야~ (포기)
unknown : 지금 당장은 잘 모르겠고 나중에 쓸 때 지정해서 쓸거야~

// unknown error 종류
error as Error
error as AxiosError

타입간 대입 가능 표


[해석방법]
any는 void에 대입 가능하다.
null은 void에 대입 불가능하다.

빈 배열 = never 이기에 never안뜨게 빈 배열일때 type지정 잘 하기!
초록색 ✔표시도 ❌

타입 좁히기(타입 가드)

function numOrStr(a: number | string) { // 매개변수로 number 혹은 string
  if (typeof a === 'string') { // a의 type 좁히기, string일 때
    a.split(',');  
  } else { // type이 number일때만 toFixed() 사용 가능
    a.toFixed(1);
  }
}

function numOrNumArr(a: number | number[]) {
  if (Array.isArray(a)) { // number[] 일때 ( 배열인지 아닌지 )
    a.slice(1);  
  } else {
    a.toFixed(1);
  }
}

class A{
	aaa() {}
}

class B{
	bbb() {}
}

function aOrB( param : A | b){
	if(param instanceof A){
    	param.aaa();
    }else{
    	param.bbb();
    }
}

aOrB(new A()) // ⭕ (인스턴스)
aOrB(b) // ❌
type B = { type: 'b', bbb: string };
type C = { type: 'c', ccc: string };
type D = { type: 'd', ddd: string };
type A = B | C | D;
// 객체들간의 값(type)으로 검사 -> 객체들간의 태그, 라벨을 달아준다!
function typeCheck(a: A) {
  if (a.type === 'b') { // type B = { type: 'b', bbb: string };
    a.bbb;
  } else if (a.type === 'c') { // type C = { type: 'c', ccc: string };
    a.ccc;
  } else { // type D = { type: 'd', ddd: string };
    a.ddd;
  }
}

// 객체들간의 속성으로 검사
function typeCheck(a: A) {
  if ('bbb' in a) { // type B = { type: 'b', bbb: string };
    a.bbb;
  } else if ('ccc' in a) { // type C = { type: 'c', ccc: string };
    a.ccc;
  } else { // type D = { type: 'd', ddd: string };
    a.ddd;
  }
}

커스텀 타입 가드(is, 형식 조건자)

is : 타입을 구분해주는 타입 가드를 커스텀 함수로 만들 수 있음

interface Cat { meow: number }
interface Dog { bow: number }
function catOrDog(a: Cat | Dog): a is Dog {
  // 타입 판별을 직접 만들기
  if ((a as Cat).meow) { return false } // a는 Dog 이기에 a가 Cat 이면 false
  return true;
}

function pet(a : Cat | Dog){
	if (catOrDog(a)) { // a:Dog
    console.log(a.bow);
  }

  // 간단하게 하려면 이렇게도 가능함
  if ('meow' in cat) {
      console.log(cat.meow);
  }
}

// PromiseSettledResult : 완료된 것
// PromiseRejectedResult : 완료된 것들 중 실패한 것
// PromiseFulfilledResult : 완료된 것들 중 성공한 것

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 fulfills = promises.filter(isFulfilled); //성공들

{}와 Object

ts 4.8 버전 업데이트와 관련된 내용

{}와 Objdect는 모든 타입( null, undefined 제외 )

//ver 4.8
const x : {} = "hello";
const y : Object = "hi";
const xx : object = "hi"; // 객체
const yy : object = {hello : "world"}; // 하지만 객체 할때는 object 지양, interface, type, class 지향
const z : unknown = "hi"; // unknown은 모든 값을 다 받을 수 있음

// unknown = {} : null | undefined
if (x){ // type unknown
	x; // type {} (모든타입)
}

readonly, 인덱스드 시그니처, 맵드 타입스

readonly : 읽기 전용 속성

interface A {
  readonly a: string;
  b: string;
}

인덱스드 시그니처 : 값에 모두 공통된 type 부여

//type A = {a: string, b: string, c: string, d: string};
type A = {[key: string] : string} // 어떤 key 든 간에 문자열, 값도 문자열

맵드 타입스 : 미리 지정한 type으로만 선언

type B = "Human" | "Mammal" | "Animal" ;
type A = {[key in B] : string} // key 가 B 중에 하나

클래스의 새로운 기능들

클래스 이름이 타입이 될 수 있다. ( new A )

class에 implements, private, protected 추가됨

interface A {
  readonly a : string;
  b:string;
}

class B implements A { // 클래스는 인터페이스를 따라야함
  private a: string; // private ( 실제 코드에서는 public )
  protected b: string; // protected
}

class C extends B {}
new C().a; // private라서 접근 불가
new C().b; // 상속받으면 접근 가능

abstract class, abstract method

abstract class X { // 추상
  abstract work(user: User): boolean; // 추상 메소드
} 
class Y extends X { // 구현
  work(user: User): boolean { // 구현 메소드
    return true;
  }
}

abstract class, abstract 생성자

const constructor: abstract new (...args: any) => any = ...

옵셔널, 제네릭 기본

? : 있어도 되고 없어도 된다.

function abc(a: number, b?: number, c: number) {}
abc(1)
abc(1, 2)
abc(1, 2, 3)

function infinite(...args: number) {} // 갯수 제한없이
infinite(1,2,3,4,5,6,7)

let obj: { a: string, b?: string }  = { a: 'hello', b: 'world' }
obj = { a: 'hello' };

제네릭: 타입에 대한 함수라고 생각하면 됨. 추론을 활용하기

function add(x: stirng|number, y: stirng|number): stirng|number {return x+y}; //❌

// 안되는 이유는 다음과 같은 결과를 기대했지만
add(1,2) // 3
add('1','2') //'12'

// 아래와 같은 경우가 발생할 수 있기 때문에 
add(1,'2')
add('1',2)

따라서 첫번째 케이스만 발생하게 하기 위해서는 제너릭 이용!
같은 타입은 하나의 동일한 문자로 표기

function add<T>(x: T, y: T): T { return x + y }
add<number>(1, 2);
add(1, 2);
add<string>('1', '2');

add('1', '2'); //❌
add(1, '2'); //❌

제네릭 선언 위치 기억하기

function a<T>() {}
class B<T>() {}
interface C<T> {}
type D<T> = {};
const e = <T>() => {};

제네릭 기본값, extends

extends : T의 값을 제한함

function add<T extends string>(x: T, y: T): T { return x + y } //T는 string만
add(1, 2);
add('1', '2')

// <T extends {...}> // 특정 객체
// <T extends any[]> // 모든 배열
// <T extends (...args: any) => any> // 모든 함수 (any: 제한없다)
// <T extends abstract new (...args: any) => any> // 생성자 타입
// <T extends keyof any> // string | number | symbol

기본값 타이핑

기본값 설정하고, 타입 지정

const A = ( a: number = 3, b: number = 5) =>{
	return '3'
}

const B = (b : (animal: string) = { animal : " cat"}) => {
}

react jsx에서는 <T><div>랑 헷갈려해서 <T - unknown>, 이렇게 기본값 넣어줌

profile
🌱 매일 성장하는 개발자

0개의 댓글