~53일차~
① Interface : extends
으로 확장
interface Animal {
name: string;
}
//extends으로 확장
interface Bear extends Animal {
honey: boolean;
}
const bear1: Bear = {
name: 'honey bear',
honey: true
}
② Type : Intersection
으로 확장
type Animal = {
name: string;
}
//Intersection으로 확장
type Bear2 = Animal & {
honey: boolean;
}
const bear: Bear = {
name: 'honey bear',
honey: true
}
① Interface : 선언 병합 가능
interface Animal {
name: string;
}
interface Animal {
honey: boolean;
}
const bear: Animal = {
name: 'honey bear',
honey: true
}
② Type : 선언 병합 불가
type Animal = {
name: string;
}
interface Animal = {
honey: boolean;
}
const bear: Animal = {
name: 'honey bear',
honey: true
}
interface getLikeNumber {
(like: number) : number;
// (매개변수)으로 작성하되 반환하는 부분의 타입은 : 으로 주기
}
interface Post {
id:number;
title: string;
getLikeNumber : getLikeNumber; //(like: number) => number;
}
const post1: Post = {
id: 1,
title: 'post 1',
getLikeNumber(like: number) {
return like;
}
}
post1.getLikeNumber(1);
interface Post {
[key: string]: unknown; //any 사용 X
id:number;
title: string;
}
const post1 = {
id: 1,
title: 'post1'
}
// [key: string]: unknown; 로 에러 발생 X
post1['description'] = 'post 1 description';
post1['pages'] = 300;
post1['pages2'] = {};
interface Names {
[item: number]: string;
//[INDEXER_NAME: INDEXER_TYPE]: RETURN_TYPE
}
const userNames: Names = ['John', 'Kim', 'Joe']
userNames[0] = 'John'
// 'John'의 item은 0,
// 'Kim'의 item은 1,
// 'Joe'의 item은 2
function add1(a: string, b: string): string {
return a + b;
}
function add2(a:number, b: number): number {
return a + b;
}
console.log(add1('hello', 'world'));
console.log(add2(1, 2));
// 위의 코드를 함수오버로딩을 이용해 아래와 같이 구현 가능
// 함수 오버로딩 1. 타입 선언 2. 함수 구현
// 타입 선언
function add(a: string, b: string): string;
function add(a: number, b: number): number;
// 함수 구현
function add(a: any, b: any): any {
return a + b;
}
function saySomething(word: string): string{
return word;
}
saySomething('Hi'); // 'Hi'
function saySomething(word: string[]): string {
return word.join(' ');
}
saySomething(['hello', 'world']); // 'hello world'
// 함수오버로딩 X union 사용
function saySomething(word: string | string[]): string {
if(typeof word === 'string') {
return word;
} else if (Array.isArray(word)) { //array인지아닌지 메소드
return word.join(' ');
}
throw new Error('unable to say something');
}
//함수오버로딩 O
function saySomething(word: string): string;
function saySomething(word: string[]): string;
function saySomething(word: any): any {
if(typeof word === 'string') {
return word;
} else if (Array.isArray(word)) { //array인지아닌지 메소드
return word.join(' ');
}
throw new Error('unable to say something');
}
① public => default 어디서든 접근 가능
② protected => 클래스 내, 상속받은 자식 클래스에서 접근 가능
③ private => 클래스 내에서만 접근 가능
this
를 사용할 경우, class body안에서 타입 지정이 필요class PostA {
//this로 접근하는 건 class body안에 타입이 지정되어야 함
private id: number = 0; // = 0 이렇게 초기화 값
protected title: string = "";
constructor(id: number, title: string) {
this.id = id;
this.title = title;
}
getPost() {
return (`postId: ${this.id}, postTitle: ${this.title}.`);
}
}
class PostB extends PostA {
getPost() { //id가 private라 error
return (`postId: ${this.id}, postTitle: ${this.title}.`);
}
}
let post: PostA = new PostA(1, "title 1");
console.log(post.id);
console.log(post.title);
PostA의 constructor 깔끔하게 정리
class PostC { constructor( private id: number = 0 , protected title: string = "" ) {} // (후략)
// arr: number[]
function getArrayLength(arr: number[]): number {
return arr.length;
}
const array1 = [1, 2, 3];
getArrayLength(array1);
//arr: number[] | string[]
function getArrayLength(arr: number[] | string[]): number {
return arr.length;
}
const array2 = ['a', 'b', 'c'];
getArrayLength(array2);
//arr: number[] | string[] | boolean[]
function getArrayLength(arr: number[] | string[] | boolean[]): number {
return arr.length;
}
const array3 = [true, false, true];
getArrayLength(array3);
// generic을 이용해서 간단하게 만들기
function getArrayLength<T>(arr: T[]): number {
return arr.length;
}
const array1 = [1, 2, 3];
getArrayLength<number>(array1);
const array2 = ['a', 'b', 'c'];
getArrayLength<string>(array2);
const array3 = [true, false, true];
getArrayLength<boolean>(array3);
interface Vehicle<T> {
name: string;
color:string;
option: T; //T로 받음
}
// 인수 타입 지정
const car: Vehicle<{ price: number }> = {
name: 'Car',
color: 'red',
option: {
price: 1000
}
}
//// 인수 타입 지정
const bike: Vehicle<boolean> = {
name: 'Bike',
color: 'green',
option: true
}
//각각 지정 :반환값에도 지정 가능
const makeArr = <T, Y = string>(x: T, y: Y): [T, Y] => {
return [x, y];
}
const array = makeArr<number, number>(4,5);
const array2 = makeArr('a', 'b'); // 위에서 기본 타입을 넣어서 생략 가능
const array3 = makeArr(4, "b");
extends
는 지정한 타입만 사용하도록 제약하는 것 //이전 (obj: {firstName: string, lastName: string})
const makeFullName = <T extends {firstName: string, lastName: string}>(obj:T) => {
return {
...obj,
fullName: obj.firstName + " " + obj.lastName
}
}
const user1 = makeFullName({firstName: 'John', lastName: 'Doe', location: 'Seoul' });
//firstName이 필수라서 없으면 error
const user2 = makeFullName({haha: 'John', lastName: 'Doe', location: 'Seoul' });
Partial< 타입 >
interface Address {
email: string;
address: string;
}
const nothing: Partial<Address> = {}; // 아예 사용하지 않아도 됨
const one: Partial<Address> = {email: "abc@example.com"}; // 부분적으로 사용 가능
const all: Address = {email: "abc@example.com", address: 'address'};
Pick< 타입, '속성1' | '속성2' >
interface Todo {
title: string;
description: string;
completed: boolean;
}
const todo: Pick<Todo, 'title' | 'completed'> = {
title: 'clean room',
completed: false
}
Omit< 타입, '속성1' >
interface Todo {
title: string;
description: string;
completed: boolean;
createdAt: number;
}
const todo: Omit<Todo, 'description'> = {
title: 'clean room',
completed: false,
createdAt: 323434
}
-Required< 타입 >
type User = {
firstName: string,
lastName?: string //? - 선택적
}
let firstUser: User = {
firstName: 'john'
}
let secondUser: Required<User> = {
firstName: 'John' // Error - lastName 필요
}
Error Message
Record<KEY, TYPE>
interface CatInfo {
age: number;
breed: string;
}
type CatName = "miffy" |"boris" | "mordred";
const cats: Record<CatName, CatInfo> = {
miffy: { age: 10, breed: "Persian" },
boris: { age: 5, breed: "Maine Coon" },
mordred: { age: 16, breed: "British Shorthair" }
}
ReturnType< TYPE >
① case 01
type T0 = ReturnType< () => string>;
//type T0 = string
type T1 = ReturnType<(s: string) => void>;
//type T1 = void
② case 02
function fn(str: string) {
return str; // 반환 타입 string
}
const a: ReturnType<typeof fn> = 'Hello';
function fn2(str: string) {
return false; // 반환 타입 boolean
}
const b: ReturnType<typeof fn2> = true;
부모 class의 프로퍼티와 메소드를 그대로 상속 받음
class Car {
mileage = 0;
price = 100;
color = 'white';
drive() {
return 'drive';
}
brake() {
return 'brake';
}
}
interface Part {
seats: number;
tire: number;
}
class Ford implements Car, Part {
mileage = 1;
price = 2;
color = 'white'; // 내용은 얼마든지 변경 가능
seats = 10;
tire = 3;
drive() {
return '24234'; // 내용은 얼마든지 변경 가능
}
brake() {
return 'sdfsdf';// 내용은 얼마든지 변경 가능
}
}
-인덱싱 가능 타입에서 keyof를 사용
-> 속성 이름을 타입으로 사용
interface IUser {
name: string;
age: number;
address: string;
}
type UserKeys = keyof IUser; // 'name' | 'age' | 'address'
const user = {
name: 'John',
age: 20,
address: 'Seoul'
}
keyof typeof
// 위의 코드 연장선 type UserKeys2 = keyof typeof user //user는 type이 아님, object // 먼저 typeof로 type을 가져온 다음, keyof로 추출 // enum 객체와 비슷하다. enum UserRole { admin, manager } // 'admin' | 'manager' type UserRoleKeys = keyof typeof UserRole;
type Subset<T> = {
[K in keyof T]?: T[K]; //여기서 ?는 프로퍼티를 선택사항으로 만들어줌
}
interface Person {
age: number;
name: string;
}
위의 타입과 인터페이스를 가지고 새로운 타입을 생성할 수 있다.
[K in keyof T]?: T[K];
① T = Person
② K = Person의 key => 'age', 'name'
③ : T[K] => age: number
, name: string
를 반환 한다
const ageOnly: Subset<Person> = { age: 23 }; // age
const nameOnly: Subset<Person> = { name: 'Tony' }; // name
const ironman: Subset<Person> = { age: 23, name: 'Tony' }; // 둘다 사용
const empty: Subset<Person> = {}; // empty
① 사용자 프로필을 조회하는 API 함수와,
interface UserProfile {
username: string;
email: string;
profilePhotoUrl: string;
}
function fetchUserProfile(): UserProfile {
// ...
}
프로필 수정하는 API 함수가 있다고 해보자.
interface UserProfileUpdate {
username?: string;
email?: string;
profilePhotoUrl?: string;
}
function updateUserProfile(params: UserProfileUpdate) {
// ...
}
② 다음과 같이 동일한 타입에 대해서 반복해서 선언하는 것을 피해야 함.
interface UserProfile {
username: string;
email: string;
profilePhotoUrl: string;
}
interface UserProfileUpdate {
username?: string;
email?: string;
profilePhotoUrl?: string;
}
③ 반복되는 구조 정리
type UserProfileUpdate = {
username?: UserProfile['username'];
email?: UserProfile['email'];
profilePhotoUrl?: UserProfile['profilePhotoUrl'];
}
④ 더욱 간결하게 만들기
type UserProfileUpdate = {
[p in 'username' | 'email' | 'profilePhotoUrl']?: UserProfile[p]
}
⑤ keyof
를 적용해서 최종 정리
type UserProfileUpdate = {
[p in keyof UserProfile]?: UserProfile[p]
}
Mapped Types 출저
https://joshua1988.github.io/ts/usage/mapped-type.html#%EB%A7%B5%EB%93%9C-%ED%83%80%EC%9E%85-%EC%8B%A4%EC%9A%A9-%EC%98%88%EC%A0%9C-2