둘째주 #9 Typescript 기초 -3

김선은·2023년 5월 24일

1. interface

  • 객체 데이터의 타입 지정 가능하다.
  • 함수 타입도 지정할 수 있다. 호출 시그니처(Call signature)
  • 인덱스 가능 타입이다. 대괄호로 속성 조회 가능. (Index Sginature)
  • 확장(상속)이 가능하다.
  • 선택적 속성 ? 과 읽기전용 속성 readonly 사용 가능.

인터페이스 사용 예시

interface User { // User 이름의 인터페이스로 객체의 키값과 타입을 지정한다
    firstName: string
    lastName: string
    age: number
    isValid: boolean
}

const heropy:User = { // 객체 형태의 함수. User를 적용했다
    firstName : 'Heropy',
    lastName : 'Park',
    age: 30,
    isValid: true
}

function getFullName(user:User) { //인수에 들어올 데이터 타입을 User로 정했다
    return `${user.firstName} ${user.lastName}` // 받은 인수의 객체 정보로 요리한다
}

const fullName = getFullName(heropy) // 리턴 함수에 인수를 넣어줌. 인수는 User 형태에 맞는 것으로.

console.log(fullName) // Heropy Park
console.log(heropy.age) // 30

인터페이스 상속과 확장

  • extends 키워드로 특정 인터페이스 속성을 그대로 받아온다.
  • 상속받은 상태에서 속성을 추가해서 새로운 인터페이스 생성 가능.
  • 확장은 같은 이름의 인터페이스에 새로운 속성과 타입을 추가로 작성할 수 있음.
  • 기존속성 + 추가속성 합쳐진다.

1-(1) 콜 시그니처(Call signature) - 함수 타입

인터페이스 안에 소괄호로 함수 타입 지정하기.
콜 시그니처는 함수 형식의 타입. type과 다르게 return 값의 타입까지 지정함.

interface GetName {
	(message: string): string
}
- 소괄호 안에 매개변수의 타입을 지정할 수 있음!
매개변수의 타입과 개수는 중요하다.

- GetName은 함수 타입! 
- 매개변수가 필요할 수 있고, 그것은 메세지이고, 타입은 string이고, 그 함수가 반환하는 값은 string이다.

type GetName {
	(message: string): string
}

interface User {
	name: string
	age: number
	getName: (message: string) => string
	// getName: GetName 위와 같은 코드임. 재사용 해야한다면 호출시그니처 
}

1-(2) 콜 시그니처(Call signature) - 인덱싱 가능 타입

  • 배열 데이터 타입을 지정할 수 있음
  • 대괄호 표기법을 통해서 숫자나 문자를 넣는 방식으로 인덱싱이 가능한 데이터 타입 지정
interface Fruits {
	[item: number]: string
}

const fruits: Fruits = [‘Apple,’ ‘Banana’, ’Cherry’]

9번강의 8번부터 예시 타이핑 해보기

-> item은 키값이 숫자이고 할당된 값은 문자 데이터이다.


제네릭

1. 제네릭 < T >

  • 콜 시그니처를 작성시 타입을 미리 알 수 없을 때!
  • 타입스크립트가 타입을 유추하고 콜 시그니처를 만듬.
  • 즉 선언 시점이 아니라 생성 시점에 들어온 값에 따라 타입을 유추해서 자동으로 명시해서 다양한 타입을 사용할 수 있도록 하는 기법
type SuperPrint = {
    (arr: number[]) : void;

}

const superPrint:SuperPrint = (arr) => {
    arr.forEach(i => console.log(i))
}

superPrint([1,2,3,4])
type SuperPotato = {
    <T>(arr: T[]): void // 리턴 있다면 T
}
// T는 배열에서 오고, 함수의 첫번째 파라미터에서 오는거라고 알려준 것
// 위와 다르게 제네릭을 사용한다고 TS에게 알려주기 위해서 <T>를 맨 앞에 붙임. (호칭 상관 X)
// 인수 타입을 concrete type이 아니라 제네릭을 써준다.
// 리턴도 void가 아니가 T를 써줄 수 있음.

const supuerPotato:SuperPotato = (arr) => {
    arr.forEach(i => console.log(i))
}

supuerPotato([1,2,true,"stirng"])

2. 함수의 오버로딩

  • 같은 함수라도 타입 유형을 여러 사용법을 만들 수 있음.
  • 같은 이름의 함수를 타입 선언을 여러 개 하고 밑에 함수 구현부분이 있으면 명시한 타입대로 구현하겠다는 의미
  • ts는 타입을 엄격하게 지정해야 하니 사용법을 여러개 만들 때 명시하는 방법
function add(a: string, b:string): string // 타입 선언1
function add(a: number, b:number): string // 타입 선언2
function add(a: any, b: any) { // 함수 구현
	return a + b
} // 함수 구현부에 any는 매개변수에 모든게 들어올 수 있다는 개념이라기 보다는 오버로딩의 문법을 통해서 위의 타입선언에 해당하는 각각의 매개변수가 함수 구현과 일치하게 만들어줄 수 있는 방법.

add(‘hello’ ,’world~’) // hello world~
add (1, 2) // 3


3. 제네릭(Generic) - 함수

  • 하나의 함수에 타입이 다양할 경우에 오버로딩 문법으로 미리 선언, 필요시 추가해야 한다.
  • 이를 개선할 수 있는게 제네릭 문법이다. 어떤 타입을 받을 지 나중에 받은 데이터로 정해짐.
  • 꺽쇠 사이에 원하는 이름을 추가하나 통상적으로 Type의 T를 쓴다.
  • 매개변수처럼 타입의 정보를 갖고 있다.
function toArray<T>(a : T, b : T) {
	return [a + b]
}

toArray(’Neo’, ’Sun’) // [‘Neo’, ‘Sun’]
toArray(1, 2) // [1, 2]
  • toArray 함수를 실행하면 ‘Neo’ 부분을 통해서 문자 데이터를 a 매개변수가 받는다
  • a의 타입이 그 때 string 타입으로 정해진다.
  • b의 타입 또한 T -> string으로 정해진다.

4. 제네릭(Generic) - 인터페이스

제네릭 문법에서의 1. 인터페이스 2. 제약 조건(Constraints) 알아보자.

  • 인터페이스에 제네릭 문법을 사용해서 만듬
  • 특정 함수에 위 인터페이스를 적용하고 원하는 타입을 그때 그때 지정할 수 있음
// 1. 인터페이스
interface MyData<T> {
	name: string
	value: T
}

const dataA: MyData<string> = {
	name: ‘Data A’
	value: ‘Hello world’ // 제네릭을 통해 문자 타입으로 만들어야 한다고 정함
}
  • 인터페이스에서 T 타입 변수에 허용할 타입을 문자와 숫자만 하고 싶다.
  • 제약 조건을 추가한다.
// 2. 제약조건
interface MyData<T extends string | number> {
	name: string
	value: T // 타입 변수에 허용할 타입만 extends 키워드를 통해 유니온으로 작성
}

polymorphism (다형성)

  • 인자들과 반환값에 대하여 형태(타입)에 따라 그에 상응하는 형태(타입)를 가질 수 있다.
  • any와의 차이점은 해당 타입에 대한 정보를 잃지 않는다.
  • any는 받았던 인수들의 타입을 활용하지 못하고 any를 반환
  • generics는 어떤 타입이든 받지만 해당 타입 정보를 알 수 있다.

요구한대로 콜 시그니처를 생성해주는 도구. 일일히 여러 타입을 미리 정하지 않아도 됨!

function superTomato<T> (a: T[]) {
    return a[0]
}

//사용 예시
type Player<E> = {
    name: string
    extraInfo: E
  // 많은 것들이 있는 큰 타입에서 한 개가 달라질 수 있는 타입이라면 제네릭 사용해서 그 타입을 재사용할 수 있음
}

const nico: Player<{favFood: string}> = {
    name: "nico",
    extraInfo: {
        favFood: "kimchi"
    }
}
profile
기록은 기억이 된다

0개의 댓글