- 1. Pick2023년 07월 22일 19시 17분 16초에 업로드 된 글입니다.작성자: sooooong_minseok
/* 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
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
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 다음글이 없습니다.이전글이 없습니다.댓글