코딩쌀롱

[TS] 타입스크립트 메모2 본문

개발공부

[TS] 타입스크립트 메모2

이브✱ 2021. 5. 21. 03:51

 

📌 인터페이스

1. 함수의 인자를 정의하는 인터페이스 (매개변수-인자, 반환값)

2. 함수 구조를 정의하는 인터페이스 

// 함수의 스펙(구조)에 인터페이스를 활용
interface SumFunction {
  (a: nubmer, b: number): number;
}

var sum: SumFunction;
sum = function(a: number, b: number): number {
  return a + b;
}

3. 인덱싱 방식을 정의하는 인터페이스

// 인덱싱
interface StringArray {
  [index: number]: string;
}

var arr: StringArray = ['a', 'b', 'c'];
arr[0] = 10; // 에러

4. 인터페이스 딕셔너리 패턴

// 딕셔너리 패턴
interface StringRegexpDictionary {
  [key: string]: RegExp;
}

var obj: StringRegexpDictionary = {
  sth: /abc/,
  cssFile: 'css', // ❌ value가 정규표현식이 아니기 때문
  jsFile: /\.js$/, // ⭕️
}

5. 인터페이스 확장(상속)

// 인터페이스 확장
interface Person {
  name: string;
  age: number;
}

interface Developer extends Person{
  language: string;
}

const capt: Developer = {
  language: 'ts',
  age: 100,
  name: '캡틴'
}

 

📌 타입 별칭(Type Aliases)

1. Type Aliases: 특정 타입이나 인터페이스를 참조할 수 있는 타입 변수.

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

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

const seho: Person ={
  name: '세호',
  age: 30
}

// 타입 변수처럼 사용
type MyString = string;
const str: MyString = 'hello';

type Todo = { id: string; title: string; done: boolean};
function getTodo(todo: Todo) {
  
}

2. type vs interface: 타입의 확장 가능 / 불가능 여부. 인터페이스는 확장이 가능한데 반해 타입은 확장이 불가능하다. 따라서 type 보다는 interfac로 선언해서 사용하는 것을 추천한다.

 

📌 연산자 이용한 타입 정의

1. 유니온 타입 장점: 파이프 기호(|)로 하나의 타입 이상을 쓸 수 있게 해 줌.

 any와 다르게 타입스크립트가 타입추론이 가능하다.

function logMessage(value: string | number) {
  if(typeof value === 'number') { // 타입 가드
    value.toLocaleString();
  }
  if(typeof value === 'string') { 
    value.toString();
  }
}
logMessage('hello');
logMessage(100);

 

2. 유니온 타입 특징: 타입스크립트 입장에서 someone 매개변수가 Developer일지, Person일지 알 수 없기 때문에, someone.skill, someone.age를 타입 검증없이 사용할 수 없다! 그래서 에러 발생. 해결하기 위해 타입가드를 사용할 수 있다. 유니온 타입의 공통된 보장된 속성만 사용 가능하다.

interface Developter {
  name: string;
  skill: string;
}

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

// 유니온 타입(|)
function askSomeone(someone: Developer | Person) {
  someone.name
  someone.skill // 에러
  someone.age   // 에러
}

 

3. 인터섹션 타입:  매개변수 someone은 Developer가 갖고 있는 name, skill, Person이 갖고 있는 name, age를 모두 포함한 3개의 속성을 갖는 타입이라는 뜻. 유니온 타입과 다르게 타입가드가 필요하지 않다. 실제로는 유니온타입을 더 많이 사용한다.

interface Developter {
  name: string;
  skill: string;
}

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

// 인터섹션 타입 (&)
function askSomeone(someone: Developer & Person) {
  someone.name
  someone.skill 
  someone.age   
}

 

4. 유니온 타입과 인터섹션 타입의 차이: 유니온 타입은 타입가드를 통해 타입추론을 해야 됨. 대신 넘겨주는 인자에 대해서 선택지가 생김. 반대로 인터섹션 타입은 두 개의 타입의 합집합인 새로운 타입을 만든 것.

 

📌 이넘(Enums)

1. 이넘: 이넘은 특정 값들의 집합을 의미하는 자료형

2. 숫자형 이넘

enum Shoes {
  Nike,
  Adidas
}
const myShoes = Shoes.Nike;
console.log(myShoes); // 0

 

 

3. 문자형 이넘

enum Shoes {
  Nike = '나이키',
  Adidas = '아디다스'
}
const myShoes = Shoes.Nike;
console.log(myShoes);  // '나이키'

 

4. 이넘 활용: 드롭다운 등의 목록이 필요할 때 이넘을 쓰는 것이 정확한 코드를 쓸 수 있고, 예외처리 케이스 줄일 수 있다.

enum Answer {
  Yes = 'Y',
  No = 'N',
}

function askQuestion(answer: string) {
  if(answer === Answer.Yes) console.log('정답')
  if(answer === Answer.No) console.log('오답')
}

askQuestion(Answer.Yes);
askQuestion('Yes'); // 에러(인자 타입이 이넘이기 떄문에 이넘만 가능)

// askQuestion('예스');
// askQuestion('y');
// askQuestion('Yes');

 

📌 타입스크립트의 클래스

1. 클래스 최상단에 멤버 변수를 정의해줘야 함.

2. 멤버 변수의 유효 범위 지정 가능(private, public)

3. readonly 접근만 가능하고 변경 불가

3. constructor 매개변수에도 타입 지정.

class Person {
  private name: stirng;
  public age: number;
  readonly log: string;

  constructor(name: string, age: number) {
    this.name = name;
    this.age = age;
  }
}

 

📌 제네릭(Generics)

1. 재사용성이 높은 컴포넌트를 만들 때 자주 활용되는 특징. 여러 타입에서 동작하는 컴포넌트를 생성할 때 사용.

function logText<T>(text: T):T {
  console.log(text);
  return text;
}
logText<string>('하이');

 

2. 기존 타입 정의 방식과 제네릭의 차이점 - 함수 중복 선언의 단점

 제네릭이 아닌 기존 타입 정의 방식을 사용하면 코드가 똑같음에도 타입에 따라 함수를 중복 선언해야한다는 단점이 있다.

 

3. 기존 문법과 제네릭의 차이점 - 유니온 타입을 이용한 선언 방식의 문제점

  인풋에 대해서는 해결이 됐지만 반환값에 있어서는 해결이 되지 않음. 인자로 string을 넘겼지만 반환값의 타입은 string | number로 돼있음. 그래서 자동완성도 string, number의 교집합만 가능하다. 그래서 string을 인자로 줬어도 string 메서드를 쓰면 에러가 발생한다.

function logText(text: string | number) {
  console.log(text);
  return text;
}

const a = logText('a');
a.split('') // 에러 발생
// 타입이 string | number이기 때문에 타입스크립트는 string이라고 확신할 수 없음

logText(10);

 

4. 제네릭의 장점과 타입 추론에서의 이점

함수를 정의할 때 타입을 비워놓은 상태, 호출할 때 타입을 지정.

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

const obj: Dropdown<number> = { value: 10, selected: false };
interface DropdownItem<T> {
  value: T;
  selected: boolean;
}

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

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

function createDropdownItem<T>(item: DropdownItem<T>) {
	...
}

emails.forEach(email => {
  const item = createDropdownItem<string>(emails);
  ...
})

 

5. 제네릭 타입 제한1: 추가적인 타입 힌트주기

function logTextLength<T>(text: T): T {
  console.log(text.length); // 에러! T가 뭔지 알 수 없기 때문에 length 속성이 있는지 알 수 없음.
  return text;
}
logTextLength<string>('hi');

// 제네릭의 타입 제한 → 배열이라는 힌트를 주고 length 속성 사용 가능
function logTextLength<T>(text: T[]): T[] {
  console.log(text.length);
  return text;
}
logTextLength<string>(['hi', 'eve']);

 

6. 제네릭 타입 제한2: 정의된 타입 이용하기

// 제네릭 타입 제한2: 정의된 타입 이용
interface LengthType {
  length: number;
}

function logTextLength<T extends LengthType>(text: T): T {
  text.length;
  return text;
}

logTextLength(10); // 에러! length 속성이 없기 때문
logTextLength({ length: 10 }); // OK! length 속성이 있는 객체기 때문

 

7. 제네릭 타입 제한3: keyof

ShoppingItem에 있는 key들 중에 한 가지가 제네릭T가 된다. → 'name', 'price', 'stock'

// 제네릭 타입 제한3: keyof
interface ShoppingItem {
  name: string;
  price: number;
  stock: number;
}

function getShoppingItemOption<T extends keyof ShoppingItem>(itemOption: T): T {
  return itemOption;
}

getShoppingItemOption('name');

 

 


참고📚

인프런 - 캡틴판교 타입스크립트 입문 강의

Comments