복습 차원에서 타입스크립트 다시 정리하기~!
인간은 망각의 동물이니까..

TS 1. interface / type / 연산자

1. interface

인덱싱 타입선언

interface StringArray {
  [index: number]: string;
}

let arr: StringArray = ['a','b','c'];
arr[0]; // 'a'
arr[0] = 10; // 타입 오류 발생 (string에 할당할 수 없다) 

딕셔너리 타입선언

interface StringRegexDictionary {
  [key: string] : RegExp; // 정규표현식 타입
}

let obj: StringRegexDictionary = {
  //sth: /abc/
  cssFile: /\.css$/, // css 파일 정규식으로 작성
  jsFile: /\.js$/, // js로 끝나는 파일
}
// 장점
Object.keys(obj).forEach(function(value){
  // 이 안에 들어오는 값들의 정의가 string이 된다 
  // 자동으로 value가 string으로 추론된다. 
})

인터페이스 확장 (상속)

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

interface Developer extends Person {
  language: string;
}

let capt: Developer = {
  // Person 타입도 추가해주어야 에러가 안난다
  name: 'juur';
  age: 22;
  language: 'ts';
}

OOP(객체지향 프로그래밍) Object Oriented Programming
무엇이냐면 !)! 정리 추가하기.

2. 타입 별칭 (Type Aliases)

타입 별칭은 특정 타입이나 인터페이스를 참조할 수 있는 타입 변수 의미

type Person = {
  name: string;
  age: number;
}

interface와 type의 차이점

  • type을 사용하면, 해당 타입 코드 전체를 바로 볼 수 있다.
  • interface는 해당 코드가 아닌 없는 변수값들을 볼 수 있다.

타입 별칭은 새로운 타입 값을 하나 생성하는 것이 아니라 정의한 타입에 대해 나중에 쉽게 참고할 수 있게 이름을 부여하는 것과 같다

interface 사용시 해당 타입 마으스오버 + command 클릭 = 바로가기
type은 확장이 되지 않는다. <가장 큰 차이점>

  • ts 공식문서 : 인터페이스는 확장이 가능한데 반해 타입 별칭은 확장이 불가능. 따라서, 가능한한 interface로 선언해서 사용하는 것을 추천한다.

3. 연산자

(1) union type(|)

타입가드 : if문 typeof로 타입확인하여 특정 동작하도록 하는 것
특정 타입으로 타입의 범위를 좁혀나가는(필터링 하는) 과정

let hee : string | number | boolean; 
const logMessage = (value: string | number) => {
  if(typeof value === 'number') {
    value.toLocaleString(); // 메소드 바로 사용 가능
  }
  if(typeof value ==='string') {
    value.toString();
  }
  throw new TypeError('value must be string or number'); // 나머지 타입은 타입에러 발생시킴
}

유니온 타입(|) 특징

| : 모든 속성 접근 가능하지 않고, 공통으로 갖고 있는 속성만 접근 가능함 혹은 타입가드이용하면 됨

(2) intersection type(&)

갖고 있는 타입 속성으로 노출되고 접근 가능
속성 중 하나라도 빠지면 타입에러 발생

TS 2. Enums

1. 이넘(Enums)

특정 값들의 집합을 의미하는 자료형 (ex. 드롭다운, 정해져있는 목록)
별도로 값 지정하지 않으면, 숫자형 0부터로 자동지정

(1) 숫자형 이넘

enum Shoes {
  Nike,
  Adidas
}

const myShoes = Shoes.Nike;
console.log(myShoes); // 0

(2) 문자형 이넘

enum Shoes {
  Nike:'나이키',
  Adidas:'아디다스'
}

const myShoes = Shoes.Nike;
console.log(myShoes); // 나이키

(3) 이넘 활용 사례

예외처리 케이스 줄어들 수 있다.

enum Answer {
  Yes ='Y', 
  No = 'N',
}
function askQuestion(answer: string) {
  // 단순히 아래처럼 문자열 비교가 아니라 enum 을 활용해서 좀 더 정확하게 
  // if (answer ==='yes') {console.log('정답입니다')}
  if (answer === Answer.Yes) {console.log('정답입니다')}
  if (answer === Answer.No) {console.log('오답입니다')}
} 
askQuestion(Answer.Yes);
//  XX => askQuestion('Yes'); // Enum 에서 제공하는 값만 넘길 수 있다.

TS 3. class ES 2015(ES6)부터 지원 - 프로토타입을 이용한 상속

1. class 역할 : 인스턴스를 만들어준다

constructor() {} => 초기화 메소드

class Person {
  // 클래스 로직  :객체 기본속성, 혹은 api 등 설정 가능
  constructor(name, age) {
    console.log('생성 되었습니다');
    this.name = name;
    this.age = age;
  }
}

const hee = new Person('hee', 300); // 생성
console.log(hee); // 객체 생성 Person {name: 'hee', age: 300}

2. class 쓰는 이유?

기본 전제 > JS가 프로토타입 기반 언어이다

자바스크립트 프로토타입 (class가 프로토타입 )
프로토타입을 이용한 상속

admin.__proto__를 통해 user를 상속받는다.
admin 객체를 추가할 수 있고, admin.name과 admin.age에도 접근 가능하다.

3. 프로토타입 활용 사례

Built-in Javascript API 또는 Javascript Native API
=> Prototype을 일상생활에서 이미 쓰고 있었다.
단순히 객체정보 확장 뿐만 아니라, 기능들을 바로 바로 쓸 수 있다.

4. ES6이전/이후 class 차이

클래스라는 것은,
기존 문법의 syntatic sugar(보기 좋은 코드) 정도의 느낌 = 추가적 기능 = 기존 제공하던 성질 변경없이 문법만 추가

1) ES6 이전

class 없이 사용 가능!

function Person(name, age) {
  this.name = name; 
  this.age = age;
}

const hee = new Person('희', 300);

2) ES6 이후

자바 개발자 혹은, 객체지향 언어 개발자들을 위해, 자바스크립트를 쓰기 수월하게 class 문법 제공한 것
하지만 babel 통해 돌려보면, 실질적으론 위처럼 생성자 함수를 썼다는 것을 알 수 있다.
기존 prototype 기반 유지, class 없이 충분히 위 함수처럼 사용 가능하다.

class Person {
  constructor(name, age) {
    this.name = name;
    this.age = age; 
  }
}

const hee = new Person('희2', 300);

5. 타입스크립트의 class

타입스크립트에선 class 최상단에 멤버변수(속성들) 타입을 선언해줘야 한다. constructor에 들어오는 파라미터 타입도 구체적으로 정할 수 있다

또, 변수의 유효 범위도 설정할 수 있다.

class Person {
  private name: string; 
  public age: number; // 기본 public
  readonly log: string; // 읽기만 가능
   
  constructor(name: string, age: number) {
    this.name = name;
    this.age = age; 
  }
}

6. 리액트 문법 : 클래스->훅 기반 함수형 코드

(1) 이전

class App extends React.Component { ... }

(2) 이후

function App() {
  return <div>Hello World</div>
}

TS 4. 제네릭

1. 제네릭 개념

타입을 마치 함수의 파라미터처럼 사용하는 것을 의미
함수의 이름 바로 뒤에 <T>라는 코드 추가. 그리고 함수의 인자와 반환 값에 모두 T라는 타입을 추가. 이렇게 되면 함수를 호출할 때 넘긴 타입에 대해 타입스크립트가 추정할 수 있게 된다.
따라서, 함수의 입력 값에 대한 타입과 출력 값에 대한 타입이 동일한지 검증할 수 있게 된다.

function logText<T>(text: T):T {
  return text; 
}

// 두 가지 방법으로 호출 가능 
// #1 호출시점 타입 넘겨주기 가능
const text = logText<string>("Hello generic!");
// #2
const text2 = logText("Hello generic!!");

2. 제네릭 장점

동일 코드를 타입을 받기 위해 불필요하게 함수 사용하는 경우를 줄일 수 있다.
만약 유니온타입으로 쓴 경우엔, 공통으로 쓸 수 있는 메소드만 미리 보여주기 가능하다.

반환값이 문자여도, number 타입을 유니온타입으로 추가해주었기에
ex.split('')사용 시, 타입오류가 뜨게 된다.
=> 제네릭 사용 시, 이런 오류가 해결된다!
같은 코드를 호출시점에 타입 정의해주어 타입추론해서 반환값까지 알 수 있게 된다.

function logText(text: string | number) {
  console.log(text);
  // text. toLocaleString / toString / valueOf 뜸
  return text; 
}

const a = logText('a');
a.split(''); // 사용 시에 반환 타입이 string/number 2개로 
// 이 부분에서 ts오류가 뜨게 된다. 

3. 제네릭 적용

interface Dropdown <T>{
  value: T,
  selected: boolean
}

const emails:Dropdown<string>[] = [
  { value: 'naver.com', selected: true },
  { value: 'gmail.com', selected: false },
  { value: 'hanmail.net', selected: false },
];

const numberOfProducts :Dropdown<number>[]= [
  { value: 1, selected: true },
  { value: 2, selected: false },
  { value: 3, selected: false },
];

function createDropdownItem<T>(item:Dropdown<T>) {
  const option = document.createElement('option');
  if(typeof item.value ==='string') {
    option.value = item.value.toString();
    option.innerText = item.value.toString();
  }
  option.selected = item.selected;
  return option;
}

// NOTE: 이메일 드롭 다운 아이템 추가
emails.forEach(function (email) {
  const item = createDropdownItem<string>(email);
  const selectTag = document.querySelector('#email-dropdown');
  selectTag?.appendChild(item);
});

4. 제네릭의 타입제한

제네릭 더 엄격하게 쓸 때!
split('') ,forEach 등 배열 메소드 사용하려고 할 때, T를 제한해서 T[]로 사용한다.

(1) T[]로 배열 메소드 사용 가능

function logTextLength<T>(text: T[]):T[] {
  console.log(text.length);
  text.forEach((text)=> console.log(text))
  return text;
}
logTextLength<string>(['hi','hee'])

(2) 정의된 타입 이용하기 (generic은 확장의 의미보단 제한의 의미다)

제네릭에 타입제한이 생긴 것!

(3) keyof로 제네릭 타입 제한하기

함수호출하는 시점 제네릭의 타입만 잘 넘겨주면 정확하게 타입 잘 선언한 모습. 인터페이스 속성만 받도록 제한하겠다.
ShoppingItem의 키들 중 한 가지가 바로 T로 들어올 것이란 의미

TS 5. 타입 추론 (type Inference)

1. 타입 추론의 기본

변수를 선언하거나 초기화 할 때 타입이 추론된다. 이외에도 변수, 속성, 인자의 기본 값, 함수의 반환 값 등을 설정할 때 타입 추론이 일어난다.

ES6-Default Value(인자 기본값 정의)

함수 호출할 때, b를 넘기지 않으면 기본적으로 10의 값을 넘긴다.
함수 내부에 변수 선언하면 c의 타입은 string, 타입 추론일어남

문자열 + 숫자 = 문자가 나오게 된다.
10 + '10' = '1010'

function getB(b=10) {
  const c = 'hi';
  return b+c; // '10hi'
}

2. 인터페이스와 제네릭을 이용한 타입 추론 방식

3. 복잡한 구조에서의 타입 추론방식

4. 가장 적절한 타입

Best Common Type : TS의 알고리즘, 가장 근접한 타입 추론
모든 값들을 union으로 묶어간다.

5. TypeScript in Visual Studio Code

https://code.visualstudio.com/docs/languages/typescript
nodeModules 하위 파일 확인하면 다음과 같다
세부 내용 읽어보고 도움될 것 같은 부분은 따로 정리하는 것으로!

TS 6. 타입 단언 (type assertion), 타입 가드

1. 타입 단언 (as 타입)

타입스크립트보다 개발자가 타입 더 잘 알 때, 타입단언 사용!

2. DOM API 조작할 때

일반적으로 document.속성에서 제공하는 속성들
웹페이지 태그정보로 접근하고, 조작할 수 있는 api
대표적으로, document.querySelector()

// DOM API 조작
// <div id = "app">hi</div>

const div = document.querySelector('div');

() 안에 'div' 선언하면 #app으로 작성했을 때보다 구체적인 태그 타입이 입력된다. vs내부에서 lib.dom.d.ts 타입이 선언되어 있기 때문이다.

div가 없을 수 있다.-> 이 경우
const div = document.querySelector('div') as HTMLDivElement;
if(div) { div.innerText } 식으로 사용

타입단언하지 않으면 null타입도 추가된다.

3. 타입 가드

유니온으로 타입이 되어 있는 경우, 공통 속성이 아니면 속성값 없다고 경고가 뜬다.

타입가드를 적용하면 에러가 뜨지 않는다 ! 예제

4. 타입 가드 실제 적용

profile
초록색 귤이 노랑색으로 익어가듯, 실력이 익어가기 위해 노력하는 개발자 초록귤입니다.

0개의 댓글

Powered by GraphCDN, the GraphQL CDN