Generic

|

코딩애플강의를 보고 정리했습니다.

Generic

재사용성 높은 컴포넌트를 만들 때 사용되며, 한가지 타입보다 여러 타입에서 동작하는 컴포넌트를 생성하는데 사용한다.

제네릭타입을(<>) 쓰면 파라미터로 타입을 입력 할 수 있다.

Ex)

function 함수<T>(x: T[]): T {
  return x[0];
}

let a = 함수 < number > [4, 2];
let b = 함수 < string > ['kim', 'park'];
  • <T>안에는 어떤 명칭이든 올 수 있다.
    예를들면 <T> 대신에 <MyType> 이런식으로 임의로 작명해도된다.
  • 제네릭으로 타입을 명시해주면 함수를 사용할때 타입을 바꿀 수 있다.

  • 일반 함수파라미터 처럼 2개 이상 넣기도 가능하다.

이건 안됨

function 함수<T>(x: T) {
  return x - 1;
}

let a = 함수 < number > 100;

function 함수<T>(x:T){...}에서는 아직 타입명이 확정된게 아니라 타입으로 string이 올 수도 있어서 에러를 낸다.

해결책으로는 narrowing(타입확정)을 해도되지만, 제네릭타입에 집어넣을 수 있는 타입을 미리 제한해주는것도 하나의 방법이다.

제네릭 타입 제한하기(constraints)

extends 문법을 쓰면 넣을 수 있는 타입을 제한할 수 있다.
일반 extends와는 달리 이건 확장이아닌, 비슷한 속성을 가지고있는지 if문으로 체크해주는 문법이다.

EX) 제네릭타입에 number타입이 있는지 체크..

function 함수<T extends number>(x: T) {
  return x - 1
}

let a = 함수<number>(100) //잘됨

class에도 제네릭 적용 가능

예시 1

class Person<T> {
  name;
  constructor(a: T) {
    this.name = a;
  }
}
let a = new Person() < string > '어쩌구';

예시 2

class GenericNumber<NumType> {
  zeroValue: NumType;
  add: (x: NumType, y: NumType) => NumType;
}

let myGenericNumber = new GenericNumber<number>();
myGenericNumber.zeroValue = 0;
myGenericNumber.add = function (x, y) {
  return x + y;
};

결론

  1. 함수에 타입파라미터를 넣을 수 있다.
  2. extends 키워드로 넣을 수 있는 타입 제한가능하다.
  3. class에도 타입파라미터 넣을 수 있다.

public,private,protected,static

|

코딩애플강의를 보고 정리했습니다.

타입스크립트에서는 자바스크립트에 없는 문법도 사용가능하다.
객체지향 언어에서 제공하는 public, private, static, protected 이런 키워드를 사용가능하다.

public, private, protected, static

public

타입스크립트는 class 안에서 public 키워드를 사용가능하다.
원하는 속성 왼쪽에 public를 붙이면 그 속성은 아무데서나 수정이 가능하다.

class User {
  public name: string;

  constructor(){
    this.name = 'kim';
  }
}

let 유저1 = new User();
유저1.name = 'park';  //가능

참고로, public는 붙이든 안붙이든 똑같다. 필드값을 그냥 만들면 public가 자동으로 부여되기 때문이다.

private

무조건 class{}중괄호 안에서만 수정 및 사용가능하게 만들어준다.
심지어 class로 부터 생산된 자식 object에서도 private이 붙은건 사용불가능하다.(class 중괄호 내부가 아니기 때문)

class User {
  public name :string;
  private familyName :string;

  constructor(){
    this.name = 'kim';
    let hello = this.familyName + '안뇽'; //가능
  }
}

let 유저1 = new User();
유저1.name = 'park';  //가능
유저1.familyName = 456; //에러남

그럼 private이 부여된 속성을 class 밖에서 수정해야할 경우 어떻게해야할까?

class User {
  public name :string;
  private familyName :string;

  constructor(){
    this.name = 'kim';
    let hello = this.familyName + '안뇽';
  }
  changeSecret(){
    this.familyName = 'park';
  }
}

let 유저1 = new User();
유저1.familyName = 'park';  //에러남
유저1.changeSecret()        //가능

class 안에 private이 부여된 속성을 변경해주는 함수를 하나 만들면된다.

protected

private랑 똑같지만(보안), extends된 class안에서도 사용가능하게 약간 보안을 풀어준다.

EX)

// 에러 안남
class User {
  protected x = 10;
}

class NewUser extends User {
  doThis(){
    this.x = 20;
  }
}

class 여러개 만들 때 class끼리 공유할 수 있는 속성을 만들고싶다면 protected를,

class 하나 안에서만 쓸 수 있는 속성을 만들고 싶으면 private를 쓰자.

static

class에 직접 변수나 함수를 부여하고 싶을때 사용

Ex)

class User {
  x = 10;
  y = 20;
}

let john = new User();

john.x; //가능
User.x; //불가능

x와 y같은 변수들은 User로부터 생성된 object들만 사용이 가능하지만, static키워드를 붙이면

class User {
  static x = 10;
  y = 20;
}

let john = new User();

john.x; //불가능
User.x; //가능

john은 사용이 불가능하게되고,
User는 직접 사용이 가능하게된다.

참고로

  • 함수도 static키워드 붙일 수 있다.
  • extends로 class를 복사할 경우 static 붙은 것들도 따라온다.
  • static는 private와 protected,public 키워드와 동시에 사용이 가능하다.
    EX)
class User {
  private static x = 10;
}

static은 언제 쓰일까?

  • class안에 간단한 메모를 할 때
  • 기본 설정 값을 입력할 때
  • class로부터 생성되는 object가 사용할 필요가 없는 변수들을 만들어놓고 싶을 때 등등…

예시)

class User {
  static skill = 'js';
  intro = User.skill + '전문가입니다';
}
var 철수 = new User();
console.log(철수);
  1. User 클래스를 만들고,
  2. 자식들에게 intro를 복사해주고 싶음
  3. js라는 단어가 중요해보여서 static skill 이곳에다가 메모 해놓고 사용
  4. 이제 자식들은 철수.intro 이렇게 사용할때 마다 ‘js 전문가입니다~’를 출력해둔다.

위에선 예시로 static을 사용했지만, constructor()를 사용하는게 더 효율적으로 보인다.

never 타입

|

코딩애플강의를 보고 정리했습니다.

결론부터

never 타입은 이럴때 지정한다.

  1. 무언가 return 하지 않고,
  2. 끝나지도 않는 함수를 표현하고 싶을 때

하지만, 2번 조건의 함수를 만들 일이 거의 없기 때문에 never타입은 쓸 일이없다.
하지만, 가끔 코드 이상하게 짜면 자동으로 등장하기 때문에 이 때 never 이게 뭘 의미하는지 이해를 하고 넘어가자.

Never type

예시

function 함수(): never {}

never타입은 아래 조건이 맞아야 사용이 가능하다.

  1. 절대 return을 하지 않아야하고,
  2. 함수 실행이 끝나지 않아야한다. (endpoint가 없어야함)

(조건 1,2는 같은 소리인데 모든 자바스크립트 함수 맨 밑엔 return undefined라는 숨겨진 코드를 갖고있어서 그렇다고한다.)

never type을 붙일수 있는것과 없는것

  • 붙일 수 없다.
// 조건1은 만족하지만, 조건2는 만족하지 않음
function 함수() {
  console.log(123);
}
  • 붙일 수 있다.
// never 가능
function 함수(): never {
  while (true) {
    console.log(123);
  }
}
// never 가능
function 함수(): never {
  throw new Error('에러메세지');
}
  • 에러가 나면 전체 코드실행이 중단되니까 2번 조건도 나름 충족되기 때문에 가능하다.

파라미터가 never 타입이 되는 경우

function 함수(parameter: string) {
  if (typeof parameter === 'string') {
    parameter + 1;
  } else {
    parameter;
  }
}

이런 경우 파라미터가 never타입이 된다.

자동으로 never 타입을 가지는 경우

function 함수() {
  throw new Error();
}

let 함수2 = function () {
  throw new Error();
};

차례대로 함수 선언문,함수 표현식인데

함수 선언문이 아무것도 리턴하지 않고 끝나지도 않을 경우 void타입이 자동으로 리턴타입으로 할당되며,

함수 표현식이 아무것도 리턴하지 않고 끝나지도 않을 경우 never타입이 자동으로 리턴타입으로 할당된다.

또는 tsconfig.json에서 strict 옵션을 켜둘 경우 함부로 any 타입을 지정해주지 않는데,

let arr = [];

원래는 any[] 이런 타입이 되지만 any 타입을 가질 수 없어서 never[] 타입이 되기도 한다.

Narrowing 심화

|

코딩애플강의를 보고 정리했습니다.

Narrowing은?

if문등으로 타입을 하나로 정해주는것을 뜻한다.

null & undefined 체크하는 법

&&기호 사용

// 예시 1
if (변수 && typeof strs === 'string') {
...
}

// 예시 2
function printAll(strs: string | undefined) {
  if (strs && typeof strs === "string") {
    console.log(s);
  }
}

in 연산자로 object 자료 narrowing

type Fish = { swim: string };
type Bird = { fly: string };
function 함수(animal: Fish | Bird) {
  if ('swim' in animal) {
    return animal.swim;
  }
  return animal.fly;
}

literal type narrowing

literal 타입이란 특정 글자나 숫자만 가질 수 있게 제한을 두는 타입 설정을 말한다.

type Car = {
  wheel: '4개',
  color: string,
};
type Bike = {
  wheel: '2개',
  color: string,
};

function 함수(x: Car | Bike) {
  if (x.wheel === '4개') {
    console.log('the car is ' + x.color);
  } else {
    console.log('the bike is ' + x.color);
  }
}

interface

|

코딩애플강의를 보고 정리했습니다.

interface

type을 이용한 타입설정과 유사함

object 자료형의 타입을 보다 편리하게 지정 가능하다.
EX)

// 마찬가지로 맨 앞글자는 대문자로써주는게 관례이다.
interface Square {
  color: string;
  width: number;
}

let 네모: Square = { color: 'red', width: 100 };

extends 가능

interface Student {
  name: string;
}
interface Teacher extends Student {
  age: number;
}

이런식으로 extends를 해주면 Teacher 타입은 age,name속성을 갖게된다.

type 키워드와 차이점?

extends 문법이 약간 다르다.

Ex) interface의 extends

interface Animal {
  name: string;
}
interface Cat extends Animal {
  legs: number;
}

Ex) type alias의 extends
(extends는 안되고, & 기호를 써서 object 두개를 합칠 수 있다. )

type Animal = {
  name: string,
};
type Cat = Animal & { legs: number };

근데, interface도 type처럼 & 기호를 이용해서 복사가능하다.

interface Student {
  name: string;
}
interface Teacher {
  age: number;
}

let 변수: Student & Teacher = { name: 'kim', age: 90 };

& 기호를 intersection이라고 부르는데, extends와 유사하게 사용가능하다.

타입이름 중복선언

Animal 타입은 name,legs 속성을 가지게 됨 type 선언을 자주 쓰는 외부 라이브러리 이용시 type 선언을 내가 덮어쓰기, override 하기 편리함

interface Animal {
  name: string;
}
interface Animal {
  legs: number;
}

interface의 경우 타입이름 중복선언을 허용해준다.
extends한 것과 동일하게 동작함

type의 경우 중복선언을 허용하지 않는다.

type으로 타입설정 같은 경우 매우 엄격하다.

// 에러남
type Animal = {
  name: string,
};
// 에러남
type Animal = {
  legs: number,
};

extends 할 때 object 안의 속성이 중복될 경우

interface Animal {
  name: string;
}
interface Dog extends Animal {
  name: number;
}

name 속성이 중복되는 상황인데, 이러면 에러가난다.

interface Animal {
  name: string;
}
interface Dog {
  name: number;
}

let 변수: Dog & Animal = { name: '멍멍' };

& 연산자로 Dog, Animal을 합쳐놓은 코드이다.
name 속성이 중복되는데, 이러면 에러가 난다.
type 키워드도 똑같음

정리

일반적인 상황에선 type 키워드를 자주 사용하는데,
다른 사람이 내 코드를 이용하는 상황이 많다면 interface로 유연하게 만드는게 좋다.
(그래서 타입스크립트로 작성된 라이브러리들은 interface로 타입 정해놓은곳이 많음)
혹은 object 자료형은 전부 interface로 만들고, 다른 자료형은 type 키워드로 만들고 이렇게 섞는것도 괜찮다고한다.
type과 interface문법을 잘 알고있다면, 기준은 정하기 나름이다.