솔미는 성장중

[TS 1주차] 타입스크립트 본문

TypeScript

[TS 1주차] 타입스크립트

solming 2023. 8. 19. 16:21
728x90

🌞 타입스크립트란?

 

정적 타입의 컴파일 언어

: 코드 작성 단계에서 타입 오류를 확인할 수 있다!

 

JS로 컴파일 후 브라우저나 Node.js환경에서 동작한다.

 

타입스크립트는 자바스크립트의 '슈퍼셋' = 완벽 호환

ts는 js기능의 모든 기능을 포함하고 있고 +a가 있다!

 

 

🌞 타입스크립트는 왜 써야할까?

 

1. 에러의 사전 방지

ex) 인자의 타입 지정 가능.

2. 코드 가이드 및 자동 완성

 

단점1. 적지 않은 학습 비용 : 타입 시스템의 이해, 기반 환경 이해 ...

단점 2. 운영 중인 서비스 적용에 대한 부담감 

 

타입스크립트 대안 JSDoc

: 코드가 길어질 수 있다는 단점을 갖고 있지만 JSDoc으로 타입스크립트가 가진 장점을 흉내낼 수 있음.

 

 

🌞 타입스크립트에서 '인터페이스'의 의미는?

 

객체 타입을 정의할 때 사용하는 문법.

인터페이스를 통해 객체의 속성과 속성 타입, 함수의 파라미터와 반환 타입, 함수의 스펙, 배열과 객체를 접근하는 방식, 클래스를 정의할 수 있다.

 

인터페이스에서 this 사용법

더보기

인터페이스에서 this 사용법

 (명식적 this) 

interface Cat {
  name: string
  age: number
}
const cat: Cat = {
  name: 'Lucy'
  age: 3
}

function hello(this:Cat, message: string){ //message는 매개변수. this는 타입을 지정해주기 위한 문법.(매개변수x)
  console.log(`Hello ${this.name}, ${message}`)
}
hello.call(cat, 'You are awesome')

 

🌞 인덱스 시그니처란?

 

 배열과 객체의 인덱싱 타입을 정의할 때 속성 이름을 정확히 명시하지 않고 속성 이름의 타입과 속성 값의 타입을 정의하는 문법.

객체와 배열을 인덱싱할 때 활용될 뿐만 아니라 객체의 속성 타입을 유연하게 정의할 때도 사용됨.

객체의 속성 이름 & 속성 값이 정해져 있으면 명시해서 정의하고 구체적으로 어떤 속성이 제공될지 알 수 없을 때 적용하면 좋다.

장점: 아래 예시에서 속성 이름이 문자열 & 속성 값이 문자열이기만 한다면 모두 추가할 수 있다!

ex)

interface SalaryInfo {
  [level: string]: stirng;
}

let salary: SalaryInfo = {
  junior: '1원',
  senior: '2원',
  ceo: '3원'
}

ex) 인덱스 시그니처가 있어서 아래 형식으로 객체를 추가하는 것이 가능

interface User {
  [key: string]: unknown,
  name: string,
  age: number
}

const solmi: User = {
  name: 'Solmi',
  age: 100,
}
solmi['isValid'] = true;
solmi['emails'] = ['ovo10203@gmail.com', 'example@gmail.com']
console.log(solmi)
/*
name:'Solmi'
age: 100
isValid: true
emails: (2) ['ovo10203@gmail.com', 'example@gmail.com']
*/

ex) 

interface Payload {
  [key: string]: unknown
}
function logValues(payload: Payload){
  for(const key in payload){ //객체데이터를 반복하는 for in 문
    console.log(payload[key]
  }
}

interface User {
  [key: string]: unknown //이게 있어야 오류가 안난다!!
  name: string
  age: number
  isValid: boolean
}

const solmi: User = {
  name: 'Solmi',
  age: 100,
  isValid: true
}
logValues(solmi)

 

 

🌜 객체 안에 key과 속성값 세트가 모두 같은 데이터 형식을 갖지 않을 수도 있잖아!

  그러면 어떻게 표현?

 

ex) 아래 객체 데이터에 대한 User라는 인터페이스를 만들어보는 상황

let solmi: User = {
  id: 'nickname',
  name: '솔미',
  22: false
}

 

1번째 시행착오: 잘못된 방식)

인덱스 시그니처를 2개 이상 써서 표현하고자 했다. (2개를 쓰는 것 자체가 틀린 것은 아님. 2번째 시행착오 참고)

interface User {
  [property: string]: string;
  [property2: number]: boolean;
  id: string;
}
let solmi: User = {
  id: 'nickname',
  name: '솔미',
  22: false
}

하지만 위 코드는 틀린 코드이다. (인덱스 시그니처를 2개 이상쓸 땐 주의할 점이 있다. 아래 이유 및 더보기 참고)
'number' 인덱스 유형 'boolean'을(를) 'string' 인텍스 유형 'string'에 할당할 수 없습니다.ts(2413)

라는 오류가 뜬다.

 

=> 이유
색인의 타입으로는 문자열 또는 숫자만이 사용 가능하다. 이 때 주의해야 할 점은 만약 문자열과 숫자를 모두 인덱스 시그니처로 사용할 경우, 숫자로 색인 된 값의 타입은 문자열로 색인 된 값 타입의 서브타입이어야 한다는 것이다   
(BA의 서브타입이다” = “B 타입의 모든 값은 A 타입에도 속한다” )

 

이러한 제약이 존재하는 이유에 대한 자세한 설명이 궁금하다면! -> 더보기 참고

더보기

이러한 제약이 존재하는 이유 (더 자세한 설명)

 

자바스크립트 색인의 동작 방식 때문!!

 

자바스크립트 코드에서 객체의 색인에 접근할 때, 내부적으로는 색인의 toString() 메소드를 호출해 문자열로 변형된 값을 색인으로 사용한다. 예를 들어 1.toString() === '1' 이므로 obj[1] 이라고 적은 코드는 실제로는 obj['1']와 동일하다.

이 때, 만약 다음 ErrorProne 타입과 같이 숫자로 색인 된 값의 타입(boolean)이 문자열로 색인된 타입(number)의 서브타입이 아닌 경우가 허용된다고 가정해보자.
 
interface ErrorProne {
[str: string]: number;
[num: number]: boolean;
}

let errorProne: ErrorProne = {
'abc': 3,
3: true
};

errorProne[3];
 
가장 아래 줄을 보면, 3이라는 색인은 숫자 타입이므로 타입 시스템은 errorProne[3]의 타입이 boolean일 것이라 추측할 것이다. 하지만 위에서 언급한 색인의 동작 방식에 의해 실제로 해당 값은 errorProne['3']과 같고, 이는 문자열 색인으로 접근한 number 타입의 값이다. 타입 시스템이 알고 있는 정보(boolean)와 실제 상황(number) 이 달라지는 것이다.
따라서 타입스크립트는 이런 코드를 작성하는 것을 허용하지 않고, error TS2413: Numeric index type 'boolean' is not assignable to string index type 'number'. 와 같은 에러를 발생시킨다. 숫자 색인으로 접근한 타입 boolean을 문자열 색인으로 접근한 타입 number에 할당할 수 없다는 의미다.
비슷한 이유로, 문자열 색인 시그니처가 존재한다면 그 외 모든 속성의 값 타입은 문자열 색인으로 접근한 값의 타입의 서브타입이여야 한다. 모든 속성 접근은 (user.name === user['name'] 이므로) 결국 문자열 색인 접근의 특수한 케이스이기 때문이다.


타입 계층 이미지

 

2번째 시행착오: 옳은 방식)

interface User {
  [property: string]: string|boolean;
  [property: number]: boolean;
  id: string;
}
let solmi: User = {
  id: 'nickname',
  name: '솔미',
  22: false
}

인덱스 시그니처를 2개 이상 써서 표현하고자 했다.

숫자로 색인된 값의 타입(boolean)이 문자열로 색인된 값의 타입(string또는 boolean)이여서 에러가 발생하지 않는다.

 

 

 

2번째 시행착오: 옳은 방식) 유니언 타입 사용하기 

interface User {
  [property: string|number]: boolean|string;
}
let solmi: User = {
  id: 'nickname',
  name: '솔미',
  22: false
}

 

 

유니언 타입 사용시 주의사항)

🎈 Key 타입은 string, number, symbol, Template literal 타입만 가능하다!

🎈 동일한 Key를 여러 개 가질 수 없다. (ex. 22: false, 22:true)

🎈 존재하지 않는 속성을 접근하면 undefined가 뜬다. (ex. solmi.email)

 

728x90