[엘리스 sw 엔지니어 트랙] 24일차 TypeScript

오경찬·2022년 5월 12일

수업 24일차

오늘은 타입스크립트 2일차이다. 어제 타입스크립트에 대해서 어떤것이고 왜쓰는지 그리고 맛보기 용으로 js의 파일을 ts로 바꾸는 실습 정도를 진행했다면 오늘은 타입스크립트에 대해 이런거 까지 있어요!! 하는 내용을 배우게 되었다.

이론

  • 타입스크립트 : 자바스크립트의 상위 집합,
    쓰는이유: 정적으로 선언가능, 타입 유추를 통한 타입 제어 가능, 오류포착 가능, js에서 찾을수 없는 추가 코드 제공
    기본 자료형: string(문자열 저장), boolean(참/거짓 저장), number(숫자 저장), null(의도적으로 비어있는), undefined(아무값이 할당x)
    참조 자료형: object(기본 자료형에 해당x), array(배열을 저장함)
    추가 제공 자료형: tuple(길이와 각요소의 타입이 정해진 배열), enum(특정 값들의 집합), any(모든 타입을 저장), void(보통 함수에서 반환값이 없을때 사용, any반대), never(발생할수 없는 타입, 종료되지 않는 함수)
    Partial< T>: 주어진 타입의 모든 하위 타입 집합을 나타내는 타입을 반환
    Readonly< T>: 프로퍼티를 읽기 전용으로 설정한 타입
    Record< T>: 타입의 프로퍼티들을 다른 타입에 매핑시키는데 사용
    Pick<T,K>: 프로퍼티 K의 집합을 선택해 타입을 구성
    Omit<T,K>: 모든 프로퍼티를 선택한 다음 K를 제거한 타입을 구성
    Exclude<T,U>: T에서 U에 할당할 수 있는 모든 속성을 제외한 타입을 구성
    Extract<T,U>: T에서 U에 할당 할 수 있는 모든 속성을 추출하여 타입을 구성
    NonNullable< T>: null과 undefined를 제외한 타입
    Parameters< T>: 함수 타입 T의 매개변수 타입들의 튜플타입을 구성
    ConstructorParameters< T>: 생성자 함수 타입의 모든 매개변수 타입을 추출
    ReturnType< T>: 함수 T의 반환 타입으로 구성된 타입을 생성
    Required< T>: T의 모든 프로퍼티가 필수로 설정된 타입을 구성
    일급 객체: 다른 객체들에 일반적으로 적용 가능한 연산을 모두 지원하는 객체
    기본 매개변수: 함수에 주어진 인자의 수는 함수가 기대하는 매개변수의 수와 일치해야 한다.
    선택적 매개변수: js에서는 모든 매개변수가 선택적으로, 인수가 없다면 undefined
    기본-초기화 매개변수: ts에서는 값을 제공하지 않거나 undefined로 했을때 매개변수의 값 할당 가능
    나머지 매개변수: 매개변수의 수를 무한으로 취급한다.
    OOP: 컴퓨터 프로그램을 객체의 모임으로 파악하려는 프로그램이 패러다임
    public: 자유롭게 접근 가능, 기본적으로 정의
    private: 클래스 외부에서의 접근을 막는다.
    protected: 맴버가 포함된 클래스와 그 하위 클래스 외부에서의 접근을 막는다.
    getters & setter: 비공개로 설정하려는 속성은 private로 설정하고, 속성값을 읽고 수정하는 getter/setter 함수를 사용한다.
    readonly: 읽기만 가능한 속성을 선언하기 위해 사용한다.
    static: 전역맴버 선언, 객체마다 할당되지 않고 클래스의 모든 객체가 공유하는 맴버
    추상클래스: 다른 클래스들이 파생될 수 있는 기초 클래스, 직접 인스턴스화 할수 없다.

TypeScript 자료형

기본 자료형

Boolean

let isDone: boolean = false;

isDone = true;

console.log(typeof isDone); //boolean

let isOk:Boolean = true;

let isNotOk:boolean = new Boolean(true); //boolean은 기본개체이지만 Bollean은 래퍼개체로 오류가 발생한다.

Number

모든 숫자는 부동 소수점 값이다.

let decimal:number = 6;
let hex:number = 0xf00d; //16진수
let binary:number = 0b1010; //2진수
let octal:number = 0o744; //8진수
let notANumber : number = NaN;
let underscoreNum :number = 1_000_000;

String

let myName: string = "Mark";
myName = "Anna";

//Template String 행에 걸쳐있거나 표현식을 넣을 수 있는 문자열 ` backquote 기호와 ${} 를 통해 사용할 수 있다.

let fullName: string = "Mark Lee";
let age: number = 30;

let sentence: string = `Hello, my name is ${fullName}. 
i'll be ${age + 1} years old next month`;

console.log(sentence); // Hello, my name is Mark Lee. i'll be 31 years old next month

Symbol

new Symbol로 사용할 수 없다. 함수로 사용해서 타입을 만들어낼 수 있다.
고유하고 수정불가능한 값으로 만들어줘 주로 접근을 제어하는데 쓰는 경우가 많다.

const sym = Symbol();
const obj = {
[sym] : "value",
};
// obj["sym"] 접근이 불가능 하다.
obj[sym]

null & undefined

tsconfig.json에서 --strictNullChecks를 사용하면 null과 undefined는 void나 자기자신에게만 할당할 수 있다.

null타입은 null값만 가질수 있으며 런타임에서의 타입은 object이다.
undefined 런타임에서의 타입은 undefined이다.

let MyName: string = null; //Error
let u:undefined = null; //Error
let v:void = undefined;

let union: string | null = null;
union = 'mark';

참조 자료형

object

primitive type이 아닌 것을 나타내고 싶을 때 사용하는 타입이다.
(non-primitive type : number,string,boolean,bigint,symbol,null or undefined)

Array

자바스트립트에서 array는 객체이다.

let list1:(number | string)[] = [1,2,3,"4"];
let list2:Array<number> = [1,2,3]; //자주 사용은 안한다.

추가 자료형

Tuple

순서와type,길이가 맞아야한다.

let x:[string,number];
x = ["hello",10];
x = [10 , "mark"]; //error
x[2] = "world"; //error

const person:[string, number]=  ['mark', 20];
const [first, second] = person;

Any

어떤 타입이어도 상관없는 타입
컴파일타임에 타입 체크가 정상적으로 이뤄지지 않아 최대한 사용하지 않는게 좋다.

function returnAny(message: any): any {
console.log(message);
}

const any1 = returnAny("리턴은 아무거나");

any1.toString();

let looselyTyped: any = {};

const d = looselyTyped.a.b.c.d;

function leakingAny(obj: any) {
const a = obj.num; //a = any
const b = a + 1; //b = any
return b;
}

const c = leakingAny({ num: 0 }); //c = any
c.indexof("0")

Unknown

모르는 타입의 변수를 지정할때 사용한다.
any와 같이 아무거나 할당할 수 있다.
컴파일러가 타입을 추론할 수 있게끔 타입의 유형을 좁히거나, 타입을 지정해주지 않으면 다른 곳에 할당 할 수 없고, 사용할 수 없다.
unknown타입을 사용하면 runtime error를 줄일수 있다.
(사용전에 데이터의 일부 유형의 검사를 수행해야하는 API에 사용한다.)

declare const maybe:unknown;

const aNumber:number = maybe;

if(maybe === true){
const aBollean:boolean = maybe; //true
// const aString:string = maybe;  error
}

if(typeof maybe === 'string'){
const aString:string = maybe // string
}

Never

모든타입에 subtype 이며, 모든 타입에 할당 할 수 있다.
never에는 그 어떤 것도 할당할 수 없다.(any도 불가능)
잘못된 타입을 넣는 실수를 막고자 사용한다.

function error(message: string): never {
  throw new Error(message);
}

function fail() {
  return error("failed"); //never
}

function infiniteLoop() :never{
  while(true){

  }
}
let a:string = 'hello';

if(typeof a !== "string") {
  //a에는 아무것도 할당할 수 없다.
}

declare const b:string|number;
if (typeof b !== "string") {
  	b //number
}

type Indexable<T> = T extends string ? T & {[index:string]:any} : never;

void

함수의 반환타입으로 사용된다.

function returnVoid (message:string):void{
console.log(message);
return; // return undefined
}
const r = returnVoid('리턴이 없다.'); //r = void 타입

유틸리티 타입

keyof

key값들을 Union형태로 받을 수 있음.

interface User {
  id: number;
  name: string;
  age: number;
  gender: "m" | "f";
}

type UserKey = keyof User; // "id" | "name" | "age" | "gender"
// keyof를 통해 User interface의 key값들을 Union 형태로 받음

const uk1:UserKey = ""; // [에러 발생]
const uk2:UserKey = "id"; // [에러 해결] User interface의 key값 중 하나 입력입력하세요

Partial< T>

모든 프로퍼티 → 옵셔널로 전환 (즉, 일부만 사용 가능)

없는 프로퍼티 사용 시 에러 발생

interface User {
    id: number;
    name: string;
    age: number;
    gender: "m" | "f";
}

// [에러 발생] 이유: age, gender 無
let admin1: User = { // 👈
    id: 1,
    name: "Bob",
};

// [에러 無]
let admin2: Partial<User> = { // 👈
    id: 1,
    name: "Bob",
};
/*
- 아래와 같음:
interface User {
    id?: number;
    name?: string;
    age?: number;
    gender?: "m" | "f";
} */

Required< T>

모든 프로퍼티 -> 필수로 전환

interface User {
    id: number;
    name: string;
    age?: number; // 👈 옵션
}

let admin: Required<User> = { // 👈
    id: 1,
    name: "Bob",
    age: 30, // 👈 Required<T>를 넣어서 age도 필수. 안 넣으면 에러 발생
}

Readonly< T>

모든 프로퍼티 → 읽기 전용으로 전환

interface User {
    id: number;
    name: string;
    age?: number;
}

// [기존] 처음 할당 후, 수정 가능
let admin1: User = {
    id: 1,
    name: "Bob",
};
admin1.id = 4;

// [적용] 처음 할당 후, 수정 불가
let admin2: Readonly<User> = {
    id: 1,
    name: "Bob",
};
admin2.id = 4; // ⛔ [id 에러 발생] 

Record<K,T>

K: key
T: type

예시1

[점수 객체 제작] 1~4학년의 점수 입력

  1. 적용전
interface Score {
    "1": "A" | "B" | "C" | "D";
    "2": "A" | "B" | "C" | "D";
    "3": "A" | "B" | "C" | "D";
    "4": "A" | "B" | "C" | "D";
}

const score: Score = {
    1: "A",
    2: "B",
    3: "C",
    4: "D",
}
  1. 리팩토링 1 | Record<K, T> 활용
    Record<키 값, 타입 값> → Record<학년, 성적>
const score: Record<'1'| '2' | '3' | '4', 'A' | 'B' | 'C' | 'D'> = {
    1: "A",
    2: "C",
    3: "B",
    4: "D",
}
  1. 리팩토링 2 | 타입(학년, 성적) 분리
    가독성 ↑
type Grade = '1' | '2' | '3' | '4' ;
type Score = 'A' | 'B' | 'C' | 'D' | 'F' ;

const score: Record<Grade, Score> = {
    1: "A",
    2: "C",
    3: "B",
    4: "D",
}

예시 2

적절한 값이 입력되었는지 체크하는 함수 제작

interface User {
    id: number;
    name: string;
    age: number;
}

function isValid(user: User) {
    const result: Record<keyof User, boolean> = {
        id: user.id > 0,
        name: user.name !== '',
        age: user.age > 0
    }
    return result
}
/*
[함수 기능]
user를 받아서 결과 객체(result) 제작 -> 조건 체크 -> 결과 리턴

[result 타입]
keyof User: result의 key는 User의 key
boolean: type은 모두 boolean */

Pick<T,K>

T타입에서 K프로퍼티만 골라서(Pick) 사용.

Omit<T, K> 반대

interface User {
    id: number;
    name: string;
    age: number;
    gender: "M" | "W"
}

const admin: Pick<User, "id" | "name"> = { // 👈 User에서 "id"와 "name"만 사용
    id: 0,
    name: "Bob"
}

Omit<T,K>

T타입에서 K프로퍼티만 생략(Omit)

Pick<T, K> 반대

interface User {
    id: number;
    name: string;
    age: number;
    gender: "M" | "W"
}

const admin: Omit<User, "age" | "gender"> = { // 👈 User에서 age & gender 제외한 나머지 사용
    id: 0,
    name: "Bob"
}

Exclude<T1,T2>

T1 타입들 중 T2타입과 겹치는 타입 제외

  • Omit과 차이

    	Omit: 프로퍼티들 제거.
    	Exclude: Type으로 제거.
// ex 1)
type T1 = string | number;
type T2 = Exclude<T1, number> // string. (T1에서 number를 제외)

// ex 2)
type T3 = string | number | boolean;
type T4 = Exclude<T3, number | string> // boolean

NonNullable< T>

null & undefined 제외한 타입 생성

type T1 = string | null | undefined | void;
type T2 = NonNullable<T1> // string | void
profile
코린이 입니당 :)

0개의 댓글