프론트엔드 - 9

송현섭 ·2023년 3월 24일

프론트엔드

목록 보기
10/24
post-thumbnail

TypeScript


Typescript 란 자바스크립트의 타입을 강제시키는 언어



TypeScript 사용 이유


  • javascript 는 type 검사가 엄격하지 않음

  • 따라서 변수, 상수를 만들면 처음에는 문자를 넣었다가, 나중에 다른 type 으로 재할당이 가능 [이런 점은 편리해 보이지만 큰 서비스 개발 시 문제발생 가능]



  • 브라우저는 HTML, CSS, Javascript 만 읽을 수 있기 때문에 Typescript는 실행 시 Javascript 로 변경되어 실행 됨
    [컴파일] => 언어가 변경되는 작업
    [트랜스파일] => 언어가 같은 언어의 다른 버전으로 변경되는 작업






TypeScript 사용 방법

  • 기존의 자바스크립트는 괜찮지만, typescript 에서는 변수에 문자열을 할당 후 다른 type 으로 재할당이 불가능 (처음 들어간 값의 type 만 가능)



  • 명시가 필요한 상황에서는 위와 같이 or 연산자로 두 가지 type 활용 가능




타입 추론

  • 변수에 type을 지정하지 않고 할당을 먼저 하게 되면 typescript 는 할당된 값의 자료형을 type으로 추론 (어림잡아 추정하게 됨)




/* 배열타입 */
// 문자열만 있는 배열
let aaa:string[] = ["원두","은정","혜원"]



// 배열에 문자열과 숫자열을 같이 넣어두고 싶을 때
let fff:(string | number)[] = [1,2,3,"철수","영희"]



// 모두 숫자이거나 모두 문자인 배열
let hhh: string[] | nuber[] =[ "영희","철수" ]
hhh=[1,2,3]
  • 배열은 type 지정 시 변수 옆에 작성 후 [ ] 를 붙여줌






  • any 타입 = 모든 type이 들어갈 수 있으나 오류의 주 원인이 될 수 있기에 가급적이면 사용 자제






  • 객체타입의 경우 interface를 이용해 type 지정 객체를 따로 만들어 줌
    [객체는 네이밍 관례가 있음 => interface의 I + 변수명]

    ex. 객체 변수이름이 Object라면 type객체의 이름은 IObject가 됨



  • 위의 경우처럼 지정한 type 객체 안에 없는 key (hobby) 를 집어넣고 값을 할당해 주려 할 경우에는 typescript가 검열을 함!
    -[이 경우 type 지정 시 객체에 [hobby?: string] 로 입력하면 있어도 되고, 없어도 되는 값으로 취급( ? => ~가 있으면 )
    -객체 생성 후 나중에 새로운 key로 hobby를 집어넣을 수 있음]








Typescript 파일 확장자


  • typescript 에는 ts, tsx 라는 두 개의 확장자가 있음

  • return 부분에 JSX 가 포함되어 있으면 tsx, 단순히 javascript 관련 기능만 있는 경우 ts 로 확장자명을 지정
    [ts 확장자는 jsx를 읽어들이지 못함!]






함수, props 의 type 지정



함수 type 지정

   const add2 = (num1: number, num2: number, unit: string): string => {
            
                return num1 + num2 + unit
            }
                
  • 함수는 각 매개변수와 return 될 값의 type을 지정해 줘야함 [return이 없을 경우 void 지정]

    -위 함수는 각 매개변수 type이 number, number, string로 지정되었고, return 값의 type은 String 으로 지정됨

    *함수의 매개변수는 암묵적으로 any로 판단됨 (함수에 따라 어떤 type이 들어갈지 알 수 없기 때문! 타입추론이 불가능)






props type 지정

//매개변수의 type 지정
const add = (a: number, b: number):number => {
  return a + b;
};

return (
    // 컴포넌트의 JSX부분
    <Component add={add} />
  );



//return 값이 없는 경우
const add = (a: number, b: number): void => {a + b};
  • 위처럼 함수를 props로 넘겨 줄 때 함수의 각 매개변수 type, return 값의 type 도 지정해줘야 함
    (return 값이 없다면 :void 입력)

    -return의 type은 생략가능(생략 시 타입추론으로 type 임의 지정)
    BUT! 오류를 방지하기 위해 명시해 주는 것이 좋음




interface IProps {
  add: (a: number, b: number) => number;
}

const Component2 = (props: IProps) => {
  props.add(1, 2);
  return (
    //컴포넌트의 JSX부분
  );
};
  • props를 상속받아 넘겨받는 컴포넌트에서는 props 의 type을 객체의 type 지정 때처럼 interface로 type객체를 만듬


  • interface 로 만드는 IProps 객체 내의 함수는 위와 같이 각 매개변수의 type을 지정해주고, return 값을 지정해 줌 (return이 없다면 void)


  • 만들어진 IProps를 props의 type 로 지정해 주고, 그 안에서 props 로 상속받은 함수 활용







Event의 type 지정

이벤트 발생 시 함수의 매개변수에 인자로 받아오는 event 객체의 type도 지정해줘야 함

  • 리액트에서 기본적으로 제공하는 기능 중 하나인 ChangeEvent 를 활용 (import로 가져올 수 있음)
    *자체적으로 event의 type을 찾아서 지정해 주는 이벤트 Type 도구






  • event: ChangeEvent<HTML inputelement> 로 event의 type을 지정
    -사용할 이벤트 type을 지정하고, < > 안에 이벤트가 발생하는 태그를 입력


    +a) < > 안의 속성은 이벤트 발생 태그에 따라 달라질 수 있음
    ex. textArea에서 이벤트 발생 =>
    <HTMLTextAreaElement>








유틸리티 Type

  • 원하는 type을 조작해서 필요한 type만 따로 빼거나, 필요없는 type만 제거할 수 있는 type

  • 지정된 타입을 만들고 약간씩의 변동으로 다른 타입을 만들 때
    굳이 매번 반복해서 비슷한 타입들을 만들지 않고 아래의 메소드들을 활용해서 구분





const profile = {
name : "철수",
	age : 12,
	school: {
		name : "다람쥐 초등학교",
		location : "서울시 구로구"
	}
}

interface IMyProfile = {
	name : string;
	age : age;
	school?: {
		name : string;
		location : string;
	}
}
  • 위와 같이 객체의 type을 만들고, 비슷한 형태에 조금씩 다른 type을 여러 개 만들 때 유틸리티를 활용해 수월한 작업기 가능







유틸리티 Type 종류

1. Partial

type profile = Partial<IMyProfile>
  • 전체 type을 optional한 type으로 변경 (모든 type에 ? 붙음, 있어도 되고 없어도 되고)



2. Required

type profile = Required<IMyProfile>
  • 전체 type을 required한 type으로 변경 (모든 type은 필수로 있어야 함)




3. Pick

type profile = Pick<IMyProfile, "name", "age">
// name과 age 타입만 지정
  • 전체 type들 중에 원하는 type만 지정
    *IMyprofile 이란 type 안에서, name과, age의 type만 지정




4. Omit

type profile = Omit<IMyProfile, "school">
// school 타입만 제거 = name과 age 타입만 지정
  • 전체 type 들 중에 원하는 type만 제거
    *IMyprofile 이란 type 안에서, school의 type만 제거



5. Union

type union = "school" | "name"
// school과 name 타입만 지정
  • 원하는 type을 직접 지정
    *ex.
    -let obj1: union (obj1은 "school", "name"만 사용가능)
    -let obj2: String (obj2는 모든 문자열 사용가능 "name","pet"... )




6. Record

type union = "school" | "name"
type RecordType = Record<union, IMyProfile>
// school과 name의 각각의 타입에는 IMyProfile가 지정
  • union으로 지정한 type을 이용해 순회하며 type 지정


    -union = 각각의 key 가 됨
    -IMyprofile= 각각의 union key 들의 값(value)이 됨






7. 객체의 key들을 이용해서 Union type 만들기

type ggg = keyof IProfile  // keyof 메소드로 IProfile의 key만 뽑아옴
let myProfile: ggg //  IProfile의 각 key인 name, age, school만 가능
  • 객체의 key 들만 keyof 메소드를 활용해 뽑아서 ggg에 담음
  • myProfile의 type으로 ggg를 지정









graphql-codegen

  • API 사용 시 rest-api 같은 경우 typescript를 적용하게 되면 모든 type을 수작업으로 만들어줘야 함


  • graphql의 경우 graphql-codegen 을 이용해 백엔드 컴퓨터에 접속해서 grphql-API 로 받아오는(요청하는) 모든 데이터의 type을 조사하고, 각각의 일치하는 ts파일을 지정한 경로에 자동으로 생성해 줌


  • 따라서 일일이 수작업으로 type을 지정할 필요 없이 필요한 type만 ts파일에서 꺼내올 수 있음








graphql에 codegen 적용 [Mutation]

// 결과타입과 변수타입은 types.ts 파일에서 import해서 데리고 오시면 됩니다.
const [함수] = useMutation<결과타입,변수타입>(쿼리);

/* 실제 코드에 적용해보기 */

// 다운로드된 타입들 중 맞는 타입을 데리고 올때는 Pick을 이용하며 해당 타입을 import해와야 합니다.
// 강의에서는 타입파일에서 Mutation과 IMutationCreateBoardArgs를 import해왔습니다.
// 우리는 IMutation 중에서 createBoard를 픽해올 것 입니다.
const [createBoard] = useMutation<Pick<IMutation, "createBoard">, IMutationCreateBoardArgs>(CREATE_BOARD);

const onClickUpload = async () => {
		const result = await createBoard(CREARTE_BOARD);
		console.log(result.data?.createBoard?.message);
	}
  • Imutation 내에 있는 여러 mutation type들 중 createBoard 를 가져옴

  • ImutationCreateBoardArgs = creatBoard 의 variables들

  • 이 두가지(IMutation 안의 createBoard, IMutationcreateBoardArgs)를 pick 해서 type으로 사용

    *Import로 가져와야 사용 가능





graphql에 codegen 적용 [Query]


 // 결과타입과 변수타입은 types.ts 파일에서 import해서 데리고 오시면 됩니다.
const { data } = useQuery<Pick<IQuery,"fetchBoard">,IQueryFetchBoardArgs>(FETCH_BOARD,{
		variables: {number: Number(router.query.mynumber)}
	})
 
  • IQuery 내의 여러 Query type들 중 fetchBoard 를 가져옴

  • IQueryFetchBoards =FetchBoards 의 variables들

  • 이 두가지(IQuery 안의 createBoard, IQueryFetchBoardsArgs)를 pick 해서 type으로 사용

    *Import로 가져와야 사용 가능

profile
막 발걸음을 뗀 신입

0개의 댓글