Typescript 강좌

개발공부·2023년 2월 19일
0

타입스크립트

목록 보기
2/8

* 출처 : 코딩앙마 유투브

1. 타입스크립트를 쓰는 이유를 알아보자

function add(num1:number, num2:number) {
    console.log(num1 + num2)
}

add(1, 2);

function showItems(arr: number[]) {
    arr.forEach((item) => {
        console.log(item)
    })
}
showItems([1, 2, 3]);

2. 타입

2-1 기본 타입

let car = 'hyundai';
let isAdult:boolean = true;

let a:number[] = [1, 2, 3]
let a2:Array<number> = [1, 2, 3]

let week1:string[] = ['mon', 'tue', 'wed'];
let week2:Array<string>  = ['mon', 'tue', 'wed'];

2-2 튜플

▶ 인덱스대로 타입이 다를 때 이용 가능

let b:[string, number];
b = ['z', 1]
// b = [1, 'z'] 오류

b[0].toLowerCase();
// b[1].toLowerCase(); 오류

2-3 void, never

▶ void : 함수에서 아무것도 반환하지 않을 때 사용
▶ never : 항상 에러를 반환하거나, 영원히 끝나지 않는 함수 타입으로 사용 가능

//void
function sayHello():void {
    console.log('hello')
}

//never
function showError():never {
    throw new Error();
}

function infLoop():never {
    while (true) {
        //do something...
    }
}

2-4 enum

▶ 비슷한 값들끼리 묶여있다고 생각하기
▶ 아무런 설정하지 않으면 0부터 시작함
▶ 문자는 단방향 매핑만 됨

enum Os {
    Window = 3,
    Ios = 10,
    Android
}

//js로 변환 시
"use strict";
var Os;
(function (Os) {
    Os[Os["Window"] = 0] = "Window";
    Os[Os["Ios"] = 1] = "Ios";
    Os[Os["Android"] = 2] = "Android";
})(Os || (Os = {}));
enum Os {
    Window = 3,
    Ios = 10,
    Android
}

console.log(Os[10]) //[LOG]: "Ios" 
console.log(Os['Ios']) //[LOG]: 10 

//js로 변환 시 
"use strict";
var Os;
(function (Os) {
    Os[Os["Window"] = 3] = "Window";
    Os[Os["Ios"] = 10] = "Ios";
    Os[Os["Android"] = 11] = "Android";
})(Os || (Os = {}));

//컴파일 되는 모습
const Os = {
     Window : 3,
    Ios : 10,
    Android : 'and'
}

* 언제 enum을 사용하는 가?
▶ 특정값만 강제하고 싶을 때
▶ 그 값들이 공통점이 있을 때

enum Os {
    Window = 'win',
    Ios = 'ios',
    Android = 'and'
}

let myOs:Os;

myOs = Os.Window

2-5. null과 undefined

let a:null = null;
let b:undefined = undefined;

3. 인터페이스

3-1 interface는 언제 사용?

property를 정의해서 객체를 표현하고 싶을 때

let user:object;

user = {
    name: 'xx',
    age: 30
}

console.log(user.name) //user.name이 없다고 나옴
interface User {
    name: string;
    age: number;
}

let user : User = {
    name: 'xx',
    age: 30
}

user.age = 10;

console.log(user.age)

3-2 옵셔널

▶ 나중에 gender 추가할 경우, 있어도 되고 없어도 되는 값

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

let user : User = {
    name: 'xx',
    age: 30
}

user.age = 10;
user.gender = 'female'

console.log(user.age)

3-3 readonly

▶ 값에 접근 가능, 수정은 불가능

interface User {
    name: string;
    age: number;
    gender? : string;
    readonly birthYear: number;
}

let user : User = {
    name: 'xx',
    age: 30,
    birthYear: 2000,
}

user.age = 10;
user.gender = 'female'
user.birthYear = 1990; //읽기 전용, 수정 불가  

console.log(user.age)
  • 여러 추가해야 할 속성
    ex) 학년별로 점수를 기입하고 싶다면?

▶ 옵셔널로 설정할 경우

interface User {
    name: string;
    age: number;
    gender? : string;
    readonly birthYear: number;
    1? : string;
    2? : string;
    3? : string;
    4? : string;
}

3-4 문자열 인덱스

interface User {
    name: string;
    age: number;
    gender? : string;
    readonly birthYear: number;
    [grade:number] : string;
}

let user : User = {
    name: 'xx',
    age: 30,
    birthYear: 2000,
    1: 'A',
    2: 'B'
}

3-5 문자열 리터럴 타입

  • 성적은 string으로 받기엔 범위가 너무 넓음
    ▶ 문자열 리터럴 타입 사용
type Score = "A" | "B" | "C" | "F"

interface User {
    name: string;
    age: number;
    gender? : string;
    readonly birthYear: number;
    [grade:number] : Score;
}

let user : User = {
    name: 'xx',
    age: 30,
    birthYear: 2000,
    1: 'A', //문제 없음
    2: 'K' //오류
}

3-6 interface로 함수 정의

interface Add {
    (num1:number, num2:number): number; 
}

const add : Add = function(x, y) {
    return x + y;
}

add(10, 20);
add(10, 20, 30); //오류

▶ boolean return

interface IsAdult {
    (age:number):boolean;
}

const a:IsAdult = (age) => {
    return age > 19;
}

console.log(a(33)) //true

3-7 클래스 정의

▶ implements 사용

//implements
interface Car {
    color: string;
    wheels: number;
    start(): void;
}

class Bmw implements Car {
    color = 'red';
    wheels = 4;
    start() {
        console.log('go...')
    }
}
//implements
interface Car {
    color: string;
    wheels: number;
    start(): void;
}

class Bmw implements Car {
    color;
    wheels = 4;
    constructor(c:string) {
        this.color = c;
    }
    start() {
        console.log('go...')
    }
}
const b = new Bmw('green')
console.log(b); 
// Bmw: {
//  "wheels": 4,
//  "color": "green"
//}

b.start(); //"go..." 

3-8 인터페이스의 확장

▶ extends 사용
▶ 기존 값(Car)과 추가로 정의 가능

//implements
interface Car {
    color: string;
    wheels: number;
    start(): void;
}

interface Benz extends Car  {
    door: number;
    stop(): void;
}

const benz : Benz = {
    door: 5,
    stop() {
        console.log('stop');

    },
    //아래를 입력하지 않으면 오류남
    color: 'red',
    wheels: 4,
    start() {
        console.log('benz start')
    }

}

▶ 확장은 여러 개가 가능

interface Car {
    color: string;
    wheels: number;
    start(): void;
}


interface Toy {
    name: string;
}

interface ToyCar extends Car, Toy {
    price: number;
}

4. 함수 타입 정의

function add(num1:number, num2: number): number {
    return num1 + num2;
} 

//아무것도 반환(return)하지 않으면 void
function add(num1:number, num2: number): void {
   console.log(num1 + num2)
} 

//boolean
function isAdult(age: number):boolean {
    return age >19;
}

4-1 함수의 매개변수

▶ 옵셔널로 지정 가능

//hello와 hello2는 모습이 같음
function hello(name?: string) {
    return `Hello, ${name || "world"}`;
}

function hello2(name = "world") {
    return `Hello, ${name}`;
}

const result = hello(); //매개변수가 없기 때문
const result2 = hello2("Sam")

console.log(result)
console.log(result2)
  • 선택적 매개변수
    ▶ 단, 필수 매개변수(name)보다 선택적 매개변수(age)이 앞에 오면 안 됨(에러 발생)
function hello(name: string, age?: number):string {
    if(age !== undefined) {
        return `Hello, ${name}. You are ${age}`
    } else {
        return `Hello, ${name}`
    }
}


console.log(hello("Sam"))
console.log(hello("Sam", 30))
  • 만약 옵셔널을 앞에 두고 필수 매개변수를 뒤에 두고 싶다면?
    ageundefined로 받게 정의하고, undefined를 전달
function hello(age: number | undefined, name: string):string {
    if(age !== undefined) {
        return `Hello, ${name}. You are ${age}`
    } else {
        return `Hello, ${name}`
    }
}


console.log(hello(30, "Sam"))
console.log(hello(undefined, "Sam"))
  • 나머지 매개변수는 매번 전달받는 숫자가 달라짐
    ...nums는 전달받은 매개변수를 배열로 나타내게 함
    ...nums: number[]
function add(...nums: number[]) {
    return nums.reduce((result, num) => result + num, 0)
}

add(1, 2, 3);
add(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);

4-2 this

▶ this의 타입을 정할 때는, 함수의 첫 번째 자리에 this를 쓰고 타입을 입력함

interface User {
    name: string;
}

const Sam: User = {name: 'Sam'}

function showName(this:User) {
    console.log(this.name)
}

const a = showName.bind(Sam);
a();
  • 만약 매개변수가 있으면?
    thisUser라고 명시하려면?
interface User {
    name: string;
}

const Sam: User = {name: 'Sam'}

function showName(this:User, age:number, gender: 'm' | 'f') {
    console.log(this.name, age, gender)
}

const a = showName.bind(Sam);
a(30, 'm');
  • 문제가 없어보는데 왜 문제가 있나?
interface User {
    name: string;
    age: number;
}

function join(name:string, age:number | string): User | string {
    if(typeof age === 'number') {
        return {
            name, age
        };
    } else {
        return "나이는 숫자로 입력해주세요";
    }
}

const sam: User = join("Sam", 30);
const jane: string = join("Jane", "30");

4-3 함수 오버로드

samUser객체를 반환하는데 확신이 없음(string을 반환할 수 있기 때문)
▶ 해결책 : 함수 오버로드
▶ 전달받은 매개변수의 개수나, 타입에 따라 다른 동작을 하게 함을 의미

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

//오버로드
function join(name:string, age:string): string;
function join(name:string, age:number): User;
function join(name:string, age:number | string): User | string {
    if(typeof age === 'number') {
        return {
            name, age
        };
    } else {
        return "나이는 숫자로 입력해주세요";
    }
}

const sam: User = join("Sam", 30);
const jane: string = join("Jane", "30");
//age가 숫자라서 User를 반환한다고 판단
//age가 문자일 경우 string를 반환한다고 판단함
profile
개발 블로그, 티스토리(https://ba-gotocode131.tistory.com/)로 갈아탐

0개의 댓글