일단 시작하는 IT개발 블로그
  • 1. Pick
    2023년 07월 22일 19시 17분 16초에 업로드 된 글입니다.
    작성자: sooooong_minseok
    1. 00004-easy-pick
    /*
      4 - Pick
      -------
      by Anthony Fu (@antfu) #쉬움 #union #built-in
    
      ### 질문
    
      `T`에서 `K` 프로퍼티만 선택해 새로운 오브젝트 타입을 만드는 내장 제네릭 `Pick<T, K>`을 이를 사용하지 않고 구현하세요.
    
      > GitHub에서 보기: https://tsch.js.org/4/ko
    */
    
    /* _____________ 여기에 코드 입력 _____________ */
    
    type MyPick<T, K> = ;
    
    /* _____________ 테스트 케이스 _____________ */
    import type { Equal, Expect } from '@type-challenges/utils'
    
    type cases = [
      Expect<Equal<Expected1, MyPick<Todo, 'title'>>>,
      Expect<Equal<Expected2, MyPick<Todo, 'title' | 'completed'>>>,
      // @ts-expect-error
      MyPick<Todo, 'title' | 'completed' | 'invalid'>,
    ]
    
    interface Todo {
      title: string
      description: string
      completed: boolean
    }
    
    interface Expected1 {
      title: string
    }
    
    interface Expected2 {
      title: string
      completed: boolean
    }

    https://typescript-kr.github.io/pages/unions-and-intersections.html


    1.  Union타입

    function logText(text: string | number) {
      // ...
    }

    | 연산자를 통해 string 또는 number 타입으로 정의.

    // any를 사용하는 경우
    function getAge(age: any) {
      age.toFixe(); // 에러 발생, age의 타입이 any로 추론되기 때문에 숫자 관련된 API를 작성할 때 코드가 자동 완성되지 않는다.
      return age;
    }
    
    // 유니온 타입을 사용하는 경우
    function getAge(age: number | string) {
      if (typeof age === 'number') {
        age.toFixed(); // 정상 동작, age의 타입이 `number`로 추론되기 때문에 숫자 관련된 API를 쉽게 자동완성 할 수 있다.
        return age;
      }
      if (typeof age === 'string') {
        return age;
      }
      return new TypeError('age must be number or string');
    }

    2. Intersection Type

    intersectionType으로 & 연산자 사용가능.

    interface Person {
      name: string;
      age: number;
    }
    interface Developer {
      name: string;
      skill: number;
    }
    type Capt = Person & Developer;
    
    
    {
      name: string;
      age: number;
      skill: string;
    }

    intersection type에서 interface로 정의된 Person과 Developer타입을 & 연산자를 통해 합집합으로 정의할 수 있다.

     

    Union Type 과 Intersection Type | 와 &연산자 그리고 인터페이스 키워드.

    Union Type은 | 연산자, Intersection Type은 &연산자.

    인터페이스 키워드를 Union과 Intersction타입으로 사용할 때는 주의가 필요함.

    interface Person {
      name: string;
      age: number;
    }
    interface Developer {
      name: string;
      skill: string;
    }
    function introduce(someone: Person | Developer) {
      someone.name; // O 정상 동작
      someone.age; // X 타입 오류
      someone.skill; // X 타입 오류
    }

    Person과 Developer단위가 아닌 name, age, skill단위로 타입을 바라보고 | 연산자를 사용한다면 &연산자처럼 보일 수 있다. 하지만 Person 타입(nams:string, age:number)이거나 Developer(name:string, skill:string) 으로 봐야만 의도된 결과를 출력할 수 있다.

     

     

    키워드 2. Utility type

    https://joshua1988.github.io/ts/usage/utility.html#%EC%9C%A0%ED%8B%B8%EB%A6%AC%ED%8B%B0-%ED%83%80%EC%9E%85%EC%9D%B4%EB%9E%80

    1. partial : 일부분의 

    existing only in part; incomplete.

    interface Address {
      email: string;
      address: string;
    }
    
    type MayHaveEmail = Partial<Address>;
    const me: MayHaveEmail = {}; // 가능
    const you: MayHaveEmail = { email: 'test@abc.com' }; // 가능
    const all: MayHaveEmail = { email: 'capt@hero.com', address: 'Pangyo' }; // 가능

    2. Pick : 선택

    interface Todo {
      title: string;
      description: string;
      completed: boolean;
    }
    
    type TodoPreview = Pick<Todo, "title" | "completed">;
    
    const todo: TodoPreview = {
      title: "Clean room",
      completed: false,
    };
    
    todo;
    // ^?

    3. Omit :생략

    leave out or exclude (someone or something), either intentionally or forgetfully.

    interface AddressBook {
      name: string;
      phone: number;
      address: string;
      company: string;
    }
    const phoneBook: Omit<AddressBook, 'address'> = {
      name: '재택근무',
      phone: 12342223333,
      company: '내 방'
    }
    const chingtao: Omit<AddressBook, 'address'|'company'> = {
      name: '중국집',
      phone: 44455557777
    }

    키워드 3. keyof and Lookup Types 

    https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-1.html#keyof-and-lookup-types

    interface Person{
        name:string;
        age:number;
        location:string;
    }
    
    type K1 = keyof Person; //"name", "age", "loaction"
    const k1:K1 = "name";
    
    type K2 = keyof Person[]; //"length", "push", "pop", "concat" ...
    const k2:K2 = "pop";
    
    type K3 = keyof {[x:string]:Person }; //string
    const k3:K3 = "asdfasdf"

    Lookup type : keyof 키워드 + 타입을 통해 어떤 타입의 property에 접근하도록 함.

    마치 객체에 key-value중 key값을 가져오는 행위와 유사한 듯 함.

    interface PersonMap{
        [x:string]:Person
    }
    
    const personMap:PersonMap = {
        I :{
            name:"song",
            age:27,
            location:"seoul"
        },
        you:{
            name:"song2",
            age:23,
            location:"seoul"
        }
    };
    
    console.log("personMap.I.age :", personMap.I.age);

    맵 형태처럼 만들 수 있다.

    interface PersonArray{
        [x:number]:Person
    }
    
    const personArray:PersonArray = [
        {
            name:"song1",age:23, location:"seoul"
        },
        {
            name:"song2", age:23, location:"seoul"
        }
    ]
    
    console.log(personArray[0]);
    //console.log(personArray.length);일반적인 배열에서 사용하는 length 등등은 사용 못하는 듯.

    배열처럼 만들 수 있지만 배열이 가지고 있는 length 등등은 사용하지 못함.

    type P1 = Person['name']; //P1 => string 
    const test1:P1 = "STRING";
    console.log("typeof ss: ", typeof test1);
    
    type P2 = Person['name' | "age"]; //P2 => string | number // union type
    const test2:P2 = "STRING";
    const test3:P2 = 2;
    console.log("test2 : ", typeof test2);
    console.log("test3 : ", typeof test3);
    
    type P3 = string["charAt"]; // P3 => (pos: number) => string // function
    const test4:P3 = stringAt;
    console.log("test4 : ", typeof test4);
    function stringAt(num:number){
        return "2";
    }
    type P4 = string[]["push"]; //P4 => (...items: string[]) => number // function
    const test5:P4 = (str:string)=>{
        return 2;
    }
    console.log("test5 : ", typeof test5);
    
    type P5 = string[][0]; // P5
    const test6:P5 = "STRING";
    console.log("test6 : ", typeof test6);
    
    //keyof key를 활용하여 typesafe한 코드 작성
    //keyof을 이용한 lookup system을 이용해야 하는 이유
    function getPropertyNoKeyof<T, K extends keyof T>(obj : T, key : K){
        return obj[key];
    }
    function setPropertyNoKeyof<T, K extends keyof T>(obj : T, key:K, value:T[K]){
        obj[key] = value;
    }
    
    const y = {foo:10, bar:"hello"};
    // const getTest2 = getPropertyNoKeyof(y, "notExistPropertyName"); //foo
    const getTest2 = getPropertyNoKeyof(y, "foo");
    // setPropertyNoKeyof(y, "foo", "string"); //number
    console.log("foo : ", typeof getTest2);

    type alias를 이용하여 해당 property가 무엇인지 알아낼 수 있다.

     

    키워드 4. Mapped Types

    Mapped types build on the syntax for index signatures, which are used to declare the types of properties which have not been declared ahead of time:

    이전에 선언되지 않은 property의 타입을 선언하기 위해 사용되어지는  index signatures 구문.

    type OnlyBoolsAndHorses = {
      [key: string]: boolean | Horse;
    };
     
    const conforms: OnlyBoolsAndHorses = {
      del: true,
      rodney: false,
    };

     

    with Mapped types, PartialPerson can be written as a generalized transformation on the type Person as:

    type Partial<T> = {
    [P in keyof T]?: T[P];
    };
    type PartialPerson = Partial<Person>;
    
    interface Person {
      name: string;
      age: number;
      location: string;
    }
    
    //>>>>>>A partial version of it would be:
    interface PartialPerson {
      name?: string;
      age?: number;
      location?: string;
    }

     

     

     


    정답.

    //Pick
    type MyPick<T, K extends keyof T> = {[P in K] : T[P]} ;
    //1. extends : 확장.
    //2. keyof T : T의 property
    //3. {[P in K] : T[P]} : Mappde Type => P in(foreach in) K(T의 property) : Person["name"] string

     

     

     

    처음 문제이지만 쉽지가 않다...

    '프로그래밍언어 > typescript' 카테고리의 다른 글

    4. First of Array  (0) 2023.08.09
    3. Tuple of Object  (0) 2023.08.09
    2. Readonly  (0) 2023.08.02
    댓글