타입스크립트 교과서 2.15~ 2.21 정리

이수빈·2023년 9월 18일
0

Typescript

목록 보기
4/17
post-thumbnail

컨디셔널 타입

  • 조건에 따라 다른 type이 되는 컨디셔널 타입 존재

  • 타입검사를 위해도 많이 사용함. (함수로도 사용이 가능할듯요)

 type A1 = string;
 type B1 = A1 extends string? number : boolean; 
    // type은 값처럼 쓸수없다. 기본삼항연산자 대신 extends 키워드를 사용해야함.

 type Result = "hi" extends string? true : false;
}

function isType<T>(value: any, targetType: { new (): T }): value is T {
  return value instanceof targetType;
}

const result1 = isType(42, Number); // true
const result2 = isType("Hello, World!", String); // true

컨디셔널 타입의 활용

특정타입 속성제거(OmitByType vs Omit)

  • 컨디셔널 타입은 never와 함께 사용가능함. => TS에서 특정타입인 속성을 제거하는 타입으로 활용가능함.

  • 타입스크립트에서 타입은 불변임. => 객체 타입에서 한 속성을을 제거하고 싶으면 기존타입을 변환하고 필터링해 새로운 타입을 만들어야 한다.

  • 매핑된 타입의 키를 never 조건부로 다시 매핑하면 해당키가 필터링됨.

  • 유틸리티 타입 Omit도 존재함. => Omit은 특정키를 기준으로 생략하여 타입을 필터링해줌.


 type OmitByType<O,T> = {
        [Key in keyof O as O[Key] extends T ? never : Key] : O[Key];
    } 
    // O의 key type들중 T type을 extend한다면, never이고 아니면 Key이다. 
    // 키가 never라면 해당 속성은 제거됨.
  
  type Result = OmitByType<"type을 생략하고 싶은 interface나 type", boolean>
// T로 넣은 타입들중 booelan 속성을 모두 제거함. 
 
interface Todo {
  title: string
  description: string
  completed: boolean
  createdAt: number
}

// description을 제외
type TodoPreview = Omit<Todo, 'description'>
  

컨디셔널 타입 + 제너릭

  • 언제사용하는가? union type으로 어떤 타입이 들어올지 특정 할 수 없을때사용

  • Start type은 string과 number의 union인데, 만약 Start가 number라면 string을 extends 하지 못하기 때문에 never로 판별됨.

  • 이럴때 제너릭을 사용해서 각각을 분배법칙처럼 분리가능함.

  • Result<string|number> => Result | Result 로 판단, Key가 string이라면 string,

    type Start = string | number; // 여기서 string[] 타입을 얻고 싶을때 
	type Result = Start extends string? Start[] : never;
    type Result<Key> = Key extends string ? Key[] : never; //Key 들이 string을 extend하면 ? string[]로 변환

    let n : Result<Start> = ["hi"]; // string[]

분배법칙을 막는경우

  • boolean에 분배법칙이 적용될 때는 조심해야함. => boolean을 false[] | true[]로 인식함
  • "hi"|3의 type검사시 => 분배법칙이 일어나서, true | false가 결과값으로 나옴 => boolean으로 인식
  • 배열로 제너릭을 감싸면 분배법칙이 일어나지 않음.
  
 	type IsString1<T> = T extends string? true:false;
    type IsString2<T> = [T] extends [string]? true:false;

    type Result1 = IsString1<"hi"|3> // boolean
    type Result2 = IsString2<"hi"|3> // false
  
  • never 타입동안 분배법칙의 대상이 됨.(모든 타입을 extend함)

함수 메서드 타이핑

  • 파라미터를 배열형식으로 받을때 튜플로 지정가능함.
  • 함수 내부에서 this를 사용하는 경우에는 명시적으로 표기해야함. (파라미터 첫번째), this가 어떤값인지 인식 할 수 없는경우 명시적으로 binding을 해줘야함.
  • 타입스크립트에서는 함수를 생성자함수로 사용 할 수 없음 => class 사용 권장
  • 메서드에서도 this사용가능함. this가 바뀔 수 있는 경우 명시적으로 타이핑해야함.
function example4(...args : [a:number, b:string, c:boolean]){
  
}

함수 오버로딩

  • TS에서 같은 이름의 함수를 여러번 선언 할 수 있다. (JS는 안됨)
  • 파라미터로 union type이 들어올때 => 이걸 일일히 타입가드해주기에는 너무 번거롭다.
    type stringNum = string|number
    function add(x:stringNum, y:stringNum):stringNum{
        if(typeof x === "number" && typeof y === "number"){
            return x+y;
        }

        ...//이렇게 4가지경우에 대해 모두 타입가드를 해줘야함.

    }
  • 인수가 숫자라면 이를 문자로, 문자라면 숫자로 리턴하는 함수를 짠다고 해보자
function switchIt(input) {
  if (typeof input === 'string') return Number(input)
  else return String(input)
}
  • 제너릭 + type assertion으로 처리
function switchIt<T extends string | number>(
  input: T,
): T extends string ? number : string {
  if (typeof input === 'string') {
    return Number(input) as string & number
  } else {
    return String(input) as string & number
  }
}

const num = switchIt('1') // has type number ✅
const str = switchIt(1) // has type string ✅
  
function switchIt_overloaded(input: string): number
function switchIt_overloaded(input: number): string
function switchIt_overloaded(input: number | string): number | string {
  if (typeof input === 'string') {
    return Number(input)
  } else {
    return String(input)
  }
}
  • 오버로딩시 좁은타입부터 넓은타입순으로 오게해야함(위에서 부터 인식하기 때문)
  • interface나 type으로도 오버로딩 구현가능함.

    interface Add{
        (x:number, y:number):number;
        (x:string, y:string):string;
    }
    const add3:Add = (x:any,y:any) => x+y;

    type Add1 = (x:number, y:number) => number;
    type Add2 = (x:string, y:string)=>string;
    type AddFn = Add1 & Add2;

    const Add4:AddFn = (x:any,y:any) => x+y

클래스

  • 내부에 type 선언하는 방식 vs interface implement하는 방식존재함 (엄밀하게 하면 interface가 코드 안정성은 높음)
  • 생성자함수를 통한 객체생성 불가능
  • class를 type으로 사용할때 => typeof 연산자 사용해야함.
  • 인스턴스를 생성할때 적용하는 타입과 class를 생성할때 적용하는 타입이 다름
  • 접근제어자 + readonly + optional을 필드에 사용가능함.
  
  class Person{
            name:string;
            married : boolean;
            age: number;
            constructor(name:string, age:number, married:boolean){
                this.name =name;
                this.age = age;
                this.married =married;
            }
        }

      class Person2{
            name;
            married;
            age;
            constructor(name:string, age:number, married:boolean){
                this.name =name;
                this.age = age;
                this.married =married;
            }
        } //생략해도 타입추론함

        const newppl = new Person2("s",12,true);  

  
        interface IPerson{
            name:string;
            married:boolean;
            age:number
        }

        class Person2 implements IPerson{
            name;
            married;
            age;
            constructor(name:string, age:number, married:boolean){
                this.name =name;
                this.age = age;
                this.married =married;
            }
        }
  
 	const person1:Person2 = new Person2("s",12,true); //인스턴스타입 

    const personClass:typeof Person2 = Person //클래스타입

private 접근제어자 vs #키워드의 차이

  • private 수식어로 선언한 속성은 자손클래스에서 같은 이름으로 선언 할 수 없음 => # 연산자 사용하기, protected만 명시적으로 사용함.
  • noImplicitOverride 옵션체크하면 함수 오버라이딩 가능함 => 부모클래스 메서드가 바뀔때 자손요소도 확인가능함.
  • 콜백함수에서 this를 활용하고 싶다면, 명시적으로 binding을 해줘야함. (첫번째 인자값으로 바인딩 할 수 있음)

enum

  • 자바스크립트에는 없는 타입이지만 자바스크립트 값으로 사용할 수 있는 특이한 타입임
  • 기본적으로 0부터 숫자할당, 문자열도 할당가능함.
  • 값보다는 타입으로 사용하는 경우가 더 많음.
  
    enum Level{
        NOVICE,
        INTERMIDIATE,
        ADVANCED,
        MASTER,
    }
  
  //JS에서 아래와 같이 컴파일됨.
  
   let Level;
    (function (Level) {
        Level[Level["NOVICE"] = 0] = "NOVICE";
        Level[Level["INTERMIDIATE"] = 1] = "INTERMIDIATE";
        Level[Level["ADVANCED"] = 2] = "ADVANCED";
        Level[Level["MASTER"] = 3] = "MASTER";
    })(Level || (Level = {}));
  
profile
응애 나 애기 개발자

0개의 댓글