TypeScript

[TypeScript] Functions

winter17 2023. 8. 3. 12:20

◆ Functions

 

▷ 숫자 타입의 함수

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

 

▷ 불리언 타입의 함수 

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

 

▷ 매개변수가 선택인 경우 

function hello(name?:string){
    // name이 있으면 name을 쓰고, 아니라면 'world'
    return `Hello, ${name || 'world'}`
}

 

▷ 매개변수에 기본값 지정 

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

 

▷ 필수 매개변수가 먼저 

function hello3(name:string, age?:number):string{
    if(age !== undefined){
        return `Hello, ${name}, You are ${age}.`
    }else{
        return `Hello, ${name}`
    }
}

 

▷ ...nums는 함수 호출 시 전달되는 인수들을 배열로 묶어서 저장하는 역할

// ...nums는 함수 호출 시 전달되는 인수들을 배열로 묶어서 저장하는 역할
function sum(...nums:number[]){
    return nums.reduce((acc, cur) => acc + cur, 0)
}

 

▷ this, bind, interface

interface User{
    name:string
}
// Sam객체는 User타입을 가진다
const Sam: User = {name:'Sam'}
// 
function showName(this:User){
    // this의 타입을 지정할 때는 가장 첫 번째 매개변수로!
    console.log(this.name)
}
// bind를 사용하여 Sam객체를 showName함수와 바인딩하여 새로운 함수 a를 생성
// bind메서드는 Sam객체를 showName함수의 this로 지정한다
const a = showName.bind(Sam)
a() 
// a를 호출하면 showName함수 내부의 console.log(this.name)에서 this는 Sam객체를 가리킨다
// 따라서 a() 함수를 호출하면 Sam객체의 name인 Sam이 출력된다

 

▷ call signatures

  • 객체가 함수처럼 호출될 수 있는 타입을 정의하는 것을 말한다
  • 함수의 시그니처와 비슷한 개념으로, 함수를 호출할 때 사용되는 매개변수의 타입 반환 타입을 명시적으로 지정하는 것
  • 콜 시그니처는 주로 인터페이스나 타입 별칭 내에서 정의된다
// Add: 콜 시그니처를 나타내는 타입 별칭의 이름
type Add = (a: number, b: number) => number
const add: Add = (a, b) => a + b

 

▷ Overload

  • 직접 오버로딩을 작성하기보다 어떻게 사용되는지에 집중할 것!
  • 함수가 여러개의 call signatures를 가지고 있을 때 발생시킴
  • 하나의 함수 이름으로 다양한 타입의 인수를 받아 다양한 방식으로 처리하는 것
// Config / Push: Call Signature
type Config = {
    path: string,
    state: object
}
type Push = {
    (path: string):void
    (config: Config): void
}

const push:Push = (config) => {
    if (typeof config === 'string') { console.log(config) }
    else {
        console.log(config.path, config.state)
        }
}

 

// 다른 call signatures에 파라미터 개수도 다른 경우
type Add = {
    (a: number, b: number): number
    // 마지막 파라미터 c는 옵션
    (a: number, b: number, c:number): number,
}

const add:Add = (a, b, c?:number) => {
    if (c) return a + b + c
    return a + b
}
add(1, 2)
add(1, 2, 3)

 

interface User{
    name: string
    age: number
}
// 오버로드
// join함수는 두 개의 오버로드 시그니처를 가지고 있다

// name, age가 모두 문자열 타입인 경우 -> 이 경우 함수는 문자열 타입 값을 반환
function join(name: string, age: string): string; 

// name은 문자열, age는 숫자인 경우 -> 이 함수는 User 인터페이스를 따르는 객체를 반환
function join(name: string, age: number): User; 

// name은 항상 문자열이어야하고, age는 숫자나 문자열 중 하나의 타입을 가질 수 있다. 
// 만약 age가 숫자 타입이라면 User 인터페이스를 따르는 객체를 반환하고
// 문자열 타입이라면 나이는 숫자로 입력해달라는 문자열을 반환한다.
function join(name: string, age: number|string):User | string{
    if(typeof age === 'number'){
        return{
            name,
            age,
        }
    }else{
        return '나이는 숫자로 입력해주세요'
    }
}
const jane: string = join('Jane', '30') // 첫 번째 시그니처 선택
const sam: User = join('Sam', 30)  // 두 번째 시그니처 선택

 

 

▷ ploymorphism(다형성)

  • 하나의 인터페이스나 기능을 여러 개체(클래스)가 다양한 방식으로 구현하는 능력
  • 코드의 재사용성과 유연성을 높여주며 객체 지향 프로그래밍의 핵심 원칙 중 하나인 '인터페이스에 의존, 구현에 의존하지 않기'를 구현하는데 도움이 된다
  • poly: many, morphos: structure → 여러가지 다른 구조/모양
  1. 컴파일 시 다형성(Compile-time Polymorphism)
    • 메서드 오버로딩(Method Overloading): 동일한 메서드 이름을 가지고 매개변수의 개수나 타입이 다른 여러 메서드를 정의하는 것, 컴파일러는 오버로딩된 메서드를 호출하는 코드를 컴파일 시점에서 정확히 파악하여 적절한 메서드를 선택한다
    • 연산자 오버로딩(Operator Overloading): 기존에 정의된 연산자를 새로운 클래스 타입에 맞게 재정의하여 사용하는 것을 말한다
  2. 런타임 시 다형성(Runtime Polymorphism)
    • 메서드 오버라이딩(Mothod Overrding): 부모 클래스에서 이미 정의된 메서드를 자식 클래스에서 동일한 시그니처로 재정의하는 것이다. 런타임 시점에서 객체의 실제 타입에 따라 적절한 메서드가 호출된다. 이는 객체 지향 프로그래밍의 상속 개념과 밀접한 관련이 있다
    • 인터페이스(interface): 다형성을 활용하기 위한 중요한 도구로 인터페이스는 클래스가 구현해야 할 메서드들의 집합을 정의한다. 클래스는 인터페이스를 구현함으로써 인터페이스에 정의된 메서드들을 재정의하고, 이를 통해 객체의 다형성을 구현할 수 있다.

▷ Generic

  • 제네릭은 타입의 placeholder 같은 존재, 자동으로 타입을 추론
  • 제네릭은 클래스나 함수를 정의할 때, 타입을 파라미터로 사용하여 여러 종류의 타입에 대해 동작하도록 설계하는 방법이다.
  • 제네릭은 선언 시점이 아니라 생성 시점에 타입을 명시하여 하나의 타입만이 아닌 다양한 타입을 사용할 수 있도록 하는 기법
  • 프로그래밍 언어에서 타입을 일반화하여 코드의 재사용성과 유연성을 높이는 기능을 말한다
  • 타입에 독립적으로 작동하는 코드를 작성할 수 있게 해 준다 → 재사용, 유지 보수성을 높임
  • concrete type: number, string, boolean, void 등
// Call Signature 타입 정의
// Generic 타입 매개변수 T를 사용하여 함수의 입력 배열과 반환 타입을 유연하게 정의할 수 있도록 한다
type SuperPrint = <T>(a: T[]):T 

// 함수 구현
const superPrint: SuperPrint = (a) => a[0]

// 변수 선언 -> 결과 타입 및 설명
const a = superPrint([1, 2, 3, 4]) // 1
const b = superPrint([true, false, true]) // true
const c = superPrint(['a', 'b', 'c']) // 'a'
const d = superPrint([1, 2, true, false]) // 1

 

// 위에서 제네릭으로 타입을 설정한 것과 같다
function superPrint<T>(a: T[]){
    return a[0]
}

 

// Player는 E라는 제네릭을 가지고 있다
type Player<E> = {
    name: string
    extraInfo: E
}
type NicoExtra = {
    favFood: string
}
type NicoPlayer = Player<NicoExtra>

const nico: NicoPlayer = {
    name: 'nico',
    extraIfo: {
        favFood: 'kimchi'
    }
}

const lynn: Player<null> = {
    name: 'lynn',
    extraInfo: null
}

 

2023.08.03 - [TypeScript] - [TypeScript] 함수 연습 문제 function, call signatures, generic