Utility Type은 기존에 있던 Type들을 변형해서 변형된 타입을 새로 만들어주는 역할을 하며,
코드의 가독성을 높이기 위해(같은 코드를 여러번 작성하지 않기 위해) 많이 사용
: 모든 속성을 선택사항으로 바꿔주는 역할
모든 속성을 필수사항으로 바꿔주는 역할 ( Partial Type과 반대 )
: 원하는 속성만을 뽑아서 사용
// index.ts
interface IProfile {
name: string;
age: number;
school: string;
hobby?: string;
}
// 3. Pick 타입
type MyType3 = Pick<IProfile, "name" | "age">;
원하는 속성만 제거하여 사용
// index.ts
interface IProfile {
name: string;
age: number;
school: string;
hobby?: string;
}
// 4. Omit 타입
type MyType4 = Omit<IProfile, "school">;
: Utility Type 속성을 다른 Type으로 매핑 시키고자 할 때 사용
Record<Key, Type>
으로 사용하며, Key로 들어온 타입을 Type 값을 가지는 타입으로 만들 수 있음
// index.ts
interface IProfile {
name: string;
age: number;
school: string;
hobby?: string;
}
// 5. Record 타입
type MyUnion = "철수" | "영희" | "훈이"; // Union 타입
type MyType5 = Record<MyUnion, IProfile>;
❓ Union Type
: Javascript의 OR 연산자(||
)와 같이 ‘A’ 이거나 ‘B’이다 라는 의미의 타입으로,
**|**
연산자를 이용하여 타입 또는 값을 여러 개 연결할 때 사용할 수 있습니다.
❓ Keyof Type
: 해당 객체 내 key값을 Union 형태로 반환시켜 주는 역할
즉, IProfile의 key만을 뽑아서 새로운 타입을 만들고 싶을때 사용
❓ type과 interface의 차이
interface는 type과 달리 선언병합이 가능
즉, IProfile을 만들어 주었는데, 또다시 IProfile을 만들어 주게 된다면
두 IProfile이 합쳐진 하나의 IProfile이 생성
=> 선언병합은 type에서 사용할 수 없음
C#, Java
등의 언어에서 재사용성이 높은 컴포넌트를 만들 때 자주 활용되는 특징
특히, 한가지 타입보다 여러 가지 타입에서 동작하는 컴포넌트를 생성하는데 사용
❓Any Type
여러 가지 타입을 허용하고 싶다면 any를 사용할 수 있음
다만, 함수의 인자로 어떤 타입이 들어갔고 어떤 값이 반환되는지는 알 수가 없음.
왜냐하면any
타입은 타입 검사를 하지 않기 때문임 => 제네릭으로 해결 가능
MongoDB 를 사용할 때는 model 파일
로 표현하여 사용하는 반면,
표 형태의 SQL DB 같은 경우에는 Entity 파일
로 표현
mysql과 연결시켜주기 위해서 TypeOrmModule
의 옵션을 설정 => app.module.ts 파일 작성
// app.module.ts
import { ApolloDriver, ApolloDriverConfig } from '@nestjs/apollo';
import { Module } from '@nestjs/common';
import { GraphQLModule } from '@nestjs/graphql';
import { TypeOrmModule } from '@nestjs/typeorm';
import { BoardModule } from './apis/boards/boards.module';
import { Board } from './apis/boards/entities/board.entity';
@Module({
imports: [
BoardModule,
GraphQLModule.forRoot<ApolloDriverConfig>({
driver: ApolloDriver,
autoSchemaFile: 'src/commons/graphql/schema.gql',
}),
TypeOrmModule.forRoot({
type: 'mysql', // 데이터 베이스 타입
host: 'localhost', // local 환경으로 진행
port: 3306, // mysql은 기본 port는 3306
username: 'root', // mysql은 기본 user는 root로 지정
password: 'root', // 본인의 mysql password
database: 'mysql', // 연결할 데이터 베이스명
entities: [Board], // 데이터 베이스와 연결할 entity
synchronize: true, // entity 테이블을 데이터베이스와 동기화할 것인지
logging: true, // 콘솔 창에 log를 표시할 것인지
}),
],
})
export class AppModule {}
// board.entity.ts
import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';
@Entity()
export class Board {
@PrimaryGeneratedColumn('increment')
number: number;
@Column()
writer: string;
@Column()
title: string;
@Column()
contents: string;
}
@Entity
: Board class가 실행될 때, typeorm에 의해 Entity 테이블을 만들어줌@PrimaryGeneratedColumn
: 자동으로 생성될 값의 컬럼increment
: 데이터가 한 줄씩 쌓일 때마다 자동으로 숫자가 1씩 증가하여 값이 생성uuid
: 중복되지 않는 문자열 ID가 자동으로 생성@Column
: 표 형태에서 열
에 해당. 실제 들어갈 데이터의 값의 컬럼ODM & ORM
- ODM ( Object Document Mapping )
: NoSQL에서 Document Database를 지원하기 위해 데이터를 변환하는 프로그래밍 기법
i.e) MongoDB 에서는 Board.save() 등을 통해 데이터 저장 기능 뿐 아니라, 데이터를 만들거나 꺼내오는 것들이 가능- ORM ( Object Relational Mapping )
: 데이터베이스와 객체 지향 프로그래밍 언어 간의 호환되지 않는 데이터를 변환하는 프로그래밍 기법
DTO (data transfer object)
: 데이터 전송 객체. 즉, 네트워크 간에 데이터를 어떤 식으로 보낼지를 정의한 객체
i.e) input
// createBoard.input.ts
import { InputType, Field } from '@nestjs/graphql';
@InputType()
export class CreateBoardInput {
@Field(() => String)
writer: string;
@Field(() => String)
title: string;
@Field(() => String)
contents: string;
}
//board.resolver.ts
import { Query, Resolver, Mutation, Args } from '@nestjs/graphql';
import { BoardService } from './board.service';
import { CreateBoardInput } from './dto/createBoard.input';
import { Board } from './entities/board.entity';
@Resolver()
export class BoardResolver {
constructor(private readonly boardService: BoardService) {}
@Query(() => [Board])
fetchBoards(){
return this.boardService.findAll();
}
@Mutation(() => String)
createBoard(
// @Args('writer') writer: string,
// @Args('title') title: string,
// @Args('contents') contents: string,
//input으로 묶어서 대신 사용
@Args('createBoardInput') createBoardInput: CreateBoardInput,
){
return this.boardService.create({
// writer,
// title,
// contents,
createBoardInput,
});
}
}
.env 사용을 위해 Nest에서 제공하는 ConfigModule을 사용
type
: type 은 무조건 mysql 을 사용한다는 의미로 as mysql 을 통해 강제 지정port
: Number()을 사용하여 string 타입을 number 타입으로 바꿔줌
- .env파일은 local 전용 파일, docker 전용 .env.docker
// app.module.ts
import { ApolloDriver, ApolloDriverConfig } from '@nestjs/apollo';
import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { GraphQLModule } from '@nestjs/graphql';
import { TypeOrmModule } from '@nestjs/typeorm';
import { BoardsModule } from './apis/boards/boards.module';
import { Board } from './apis/boards/entities/board.entity';
@Module({
imports: [
BoardsModule,
ConfigModule.forRoot(),
GraphQLModule.forRoot<ApolloDriverConfig>({
driver: ApolloDriver,
autoSchemaFile: 'src/commons/graphql/schema.gql',
}),
TypeOrmModule.forRoot({ //.env 파일 사용하여 기밀 유지
type: process.env.DATABASE_TYPE as 'mysql',
host: process.env.DATABASE_HOST,
port: Number(process.env.DATABASE_PORT),
username: process.env.DATABASE_USERNAME,
password: process.env.DATABASE_PASSWORD,
database: process.env.DATABASE_DATABASE,
entities: [Board],
synchronize: true,
logging: true,
}),
],
})
export class AppModule {}
Docker로 서버를 올리기 위해선, Docker를 위한 설정 파일 3개 필요
- .dockerigonre, docker-compose.yaml, Dockefile
// .dockerignore
node_modules
dist
# docker-compose.yaml
version: '3.7'
services:
my-backend:
build:
context: .
dockerfile: Dockerfile
volumes:
- ./src:/myfolder/src
ports:
- 3000:3000
env_file:
- ./.env.docker
my-database:
image: mysql:latest
platform: linux/x86_64
environment:
MYSQL_DATABASE: 'mydocker'
MYSQL_ROOT_PASSWORD: 'root'
ports:
- 3306:3306
my-database
platform: linux/x86_64
: 맥북 M1 칩을 사용하시는 분이라면 추가 설정image
: mysql 최신버전으로 설정environment
: MySQL 설치 시, 초기 셋팅을 위한 곳으로 DB 이름과 DB 비밀번호롤 작성
- DB 이름은
.env.docker
파일의 DATABASE_DATABASE 와 동일해야 하며,
DB 비밀번호는.env.docker
파일의 DATABASE_PASSWOR 와 동일