A Developing Developer
DAY 51. TypeScript 심화 2일차 본문
- 문제발생
TypeScript (제네릭 타입, 유틸리티 타입)
- 시도
-
- 해결방안
-
- 알게 된 것
1. 제네릭 타입 (Generic Types) : 선언 시점이 아닌 생성 시점에 타입을 명시하여 하나의 타입만이 아닌 다양한 타입을 사용할 수 있게 해주는 기법! (대표적 식별자 T, 그외 U, V 가 있지만 관용적인 식별자인 T 를 쓴다)
- 객체
interface MyInterface<GenericValue> {
value: GenericValue;
}
const stringObject: MyInterface<string> = { value: "hello, world!" };
const numberObject: MyInterface<number> = { value: 1234 };
const stringArrayObject: MyInterface<Array<string>> = { // MyInterface<string[]> 기능적으로는 동일
value: ["hello", "world!"],
};
// 재활용, 무슨타입을 명시했는지 보기 쉽다.
- 함수
type User = {
email: string;
name: string;
};
// 타입 변수, 캡처를해서 넘겨주고, 반환 타입 T
function getData<T>(data: T): T {
return data;
}
// 에러 없이 콘솔로그 되는 유효한 호출
console.log(getData<string>("string data"));
console.log(getData<number>(1234));
console.log(getData<User>({ email: "email@email.com", name: "katie" }));
console.log(getData<string[]>(["string", "data"]));
console.log(getData<string[]>([])); // 빈 배열도 유효한 인자입니다!
- 클래스
interface IStack<T> {
push(item: T): void;
pop(): T | undefined;
peek(): T | undefined;
size(): number;
}
class Stack<T> implements IStack<T> {
private storage: T[] = [];
// storage 배열의 길이를 4로 제한
constructor(private capacity = 4) {}
// storage 배열에 인자로 받는 item 값을 담아주는 함수
push(item: T): void {
if (this.size() === this.capacity) {
throw Error("stack is full");
}
this.storage.push(item);
}
// storage 배열의 제일 마지막에 위치한 값을 뽑아내는 함수
pop(): T | undefined {
return this.storage.pop();
}
// storage 배열의 마지막 index에 위치한 값을 다루는 함수
peek(): T | undefined {
return this.storage[this.size() - 1];
}
// storage 배열의 길이를 반환하는 함수
size(): number {
return this.storage.length;
}
}
const numberStack = new Stack<number>();
numberStack.push(1);
numberStack.push(2);
numberStack.push(3);
numberStack.push(100);
console.log(numberStack.peek()); // 100
console.log(numberStack.size()); // 4
// 이미 4개의 값이 stroage 배열에 가득차있으므로, 하나의 값을 더 추가하면 에러발생
// numberStack.push(101); // ❌ Error: stack is full
2. 유틸리티 타입 (Utility Types) : 외부 라이브러리에서 불러오는 타입이나 import 해올 수 없는 타입을 조작해서 원하는 타입으로 변환시키는데 유용하다.
- Partial<Type> : 특정 타입에 속해있는 집합을 모두 선택적으로 만드는 타입으로 변환
interface Toppings {
tomatoes: boolean;
onion: boolean;
lettuce: boolean;
ketchup: boolean;
}
// 모든 타입을 반드시 명시
const toppingsIWant: Toppings = {
tomatoes: true,
onion: true,
lettuce: true,
ketchup: true,
};
// 모든 타입을 선택적 명시
const partialToppingsIWant: Partial<Toppings> = {
tomatoes: true,
onion: undefined,
};
console.log("wt", partialToppingsIWant);
- Required<Type> : Partial 의 반대! 특정 타입에 속해있는 집합을 모두 필수로 변환하는 타입!
// 선택적으로
interface BubbleTeaOrder {
tea: boolean;
straw?: boolean;
}
// 필수!
const myBubbleTeaOrder: Required<BubbleTeaOrder> = {
tea: true,
straw: true,
};
// 선택적!
const myBubbleTeaOrder2 = {
tea: true,
};
// 라이브러리를 가져와서 쓰는 경우가 많은데, 해당 라이브러리에서 export 해주는 타입만 사용가능한데, 사용하고자 하는 용도에 맞게 쓰기위해서는 유틸리티 타입을 이용해야한다. (지정된 타입 조작)
- Readonly<Type> : 한 타입의 집합을 읽기권한만 가능하게 변환해주는 타입
interface BankAccount {
accountNumber: string;
balance: bigint;
}
const myAccount: Readonly<BankAccount> = {
accountNumber: "1234",
balance: BigInt(Number.MAX_SAFE_INTEGER),
};
// 컴파일되지 않습니다
//myAccount.accountNumber = "123"; // ❌ Cannot assign to 'accountNumber' because it is a read-only property.
//myAccount.balance = BigInt(Number.MIN_VALUE); // ❌ Cannot assign to 'balance' because it is a read-only property.
console.log(myAccount);
- Record<Keys, Type> : 객체 타입을 설립하는데 쓰임
type Type = string[];
type TypeII = Array<string>;
type ObjectTypeRecord = Record<string, string>;
type ObjectTypeObject = { [x: string]: string };
type Country = "Korea" | "USA" | "Canada" | "UK"; // enum으로 구현해도 됩니다
type CountryCode = 82 | 1 | 44; // enum으로 구현해도 됩니다
// syntaxt 객체 문법
type CountryToCountryCode = Record<Country, CountryCode>;
const countries: CountryToCountryCode = {
Korea: 82,
USA: 1,
Canada: 1,
UK: 44,
};
- Omit<Type, keys> : 특정 타입에 구성되어있는 프로퍼티를 생략시킬 때 쓰는 타입!
interface UserInfo {
userName: string;
favoriteColor: string;
email: string;
password: string;
}
type LessUserInfo = Omit<UserInfo, "password" | "email">;
const newUser: LessUserInfo = {
userName: "pony",
favoriteColor: "rainbow",
// 생략시킨 email이 속해있어서 컴파일되지 않습니다
//email: "hello@world.hello", // ❌ Object literal may only specify known properties, and 'email' does not exist in type 'LessUserInfo'.
};
// UserInfo 는 조작되지않고 새로운 타입을 만든다.
- Exclude<UnionType, ExcludeMembers> : 유니언 타입에 속해있는 속성들을 생략할 때 사용, Omit 은 객체 타입
type MyType = "dog" | "cat" | "alpaca";
type ExcludedType = Exclude<MyType, "cat" | "alpaca">;
type LessMyType = Exclude<MyType, "alpaca">;
const onlyDogAllowed: ExcludedType = "dog"; // ✅
//const noAlpaca: ExcludedType = "alpaca"; // ❌
const catOrDogAllowed: LessMyType = "cat";
//----------------------------------------------------
type OnChange = (isDone: boolean) => boolean;
type GroupOfTypes = string | undefined | OnChange;
type FunctionType = Exclude<GroupOfTypes, string | undefined>; // Onchange 만 남음
const onChangeHandler: FunctionType = (isDone) => isDone; // ✅
console.log(onChangeHandler(true));
//const today: FunctionType = "greate day"; // ❌
// Onchange 타입을 반영해서 오른쪽이 함수여야 함
- Pick<Type, Keys> : 한 타입의 특정 프로퍼티들만 뽑아쓸수 있도록 도와주는 타입! Omit 의 반대!
interface User {
firstName: string;
lastName: string;
}
interface Student {
user: User;
isGraduated: boolean;
school: string;
}
type StudentName = Pick<Student, "user" | "isGraduated">;
const studentName: StudentName = {
user: {
firstName: "winnie",
lastName: "pooh",
},
isGraduated: true,
};
console.log(studentName);
- Extract<Type, Union> : 타입에서 필요한 유니언만 뽑아쓴다! Exclude 는 생략! (약간 반대라고 생각하면?)
type MyPet = "dog" | "cat" | "alpaca";
type ExtractedType = Extract<MyPet, "alpaca" | "cat">;
const onlyAlpacaOrCatAllowed: ExtractedType = "cat"; // 또는 "alpaca"만 할당 가능
console.log(onlyAlpacaOrCatAllowed);
- NonNullable<Type> : 특정 타입에서 null 또는 undefined 를 생략해주는 타입! 생략보다는 null 과 undefined 를 쓸수 없게하는 거 같은데?
type QueryParam = string | string[] | undefined | null;
type NonNullableQueryParam = NonNullable<QueryParam>;
const queryParam: NonNullableQueryParam = "orders"; // 문자열은 허용되는 타입입니다
// const forbiddenQueryParam: NonNullableQueryParam = undefined;
// 허용되지 않는다
[결론]
https://www.typescriptlang.org/ko/docs/handbook/utility-types.html
외에도 공부할거 많다...
개발자... 진짜 관둘때까지 공부해야하는 직업이라할만 하다.
'내일배움캠프 4기 > TIL' 카테고리의 다른 글
DAY 57. SOLID 원칙 (0) | 2023.02.06 |
---|---|
1.27 ~ 2.3 나태지옥 (0) | 2023.02.06 |
DAY 50. TypeScript 심화 1일차 (0) | 2023.01.26 |
DAY 49. TypeScript 5일 (0) | 2023.01.20 |
DAY 48. TypeScript 4일차 (0) | 2023.01.19 |