728x90

In Typescript, the exclamtion is sometimes used in last of the characters.

For example,

const people = { name: 'kim' };

if (people.name!) {
  ...
}

what is meaning?

In TypeScript, the exclamation mark (!) is used to assert that a value is not null or undefined. It is called the non-null assertion operator. However, it is typically used when you are certain that the value will not be null or undefined, and it should be used with caution.

728x90
반응형

'개발, 코딩 > typescript' 카테고리의 다른 글

typescript, 제네릭에대해 알아보자  (0) 2022.11.10
optional과 undefined의 차이  (0) 2022.10.26
typescript, 타입 소개  (0) 2022.10.26
728x90

동일한 정규식에 동일한 값을 넘겼음에도

반복해서 true, false를 번갈아 반환했다.

대체 왜!!!

 

이유

정규식에 g 옵션이 있으면, test() 메소드는 정규 표현식의 lastIndex를 업데이트하게 된다.

test() 메소드와 exec() 메소드는 내부적으로 lastIndex부터 문자열을 검사하게 되는데,

test() 메소드는 true를 반환했던 lastIndex부터 계속해서 검사하게 된다.

 

그리고 lastIndex는 false를 반환하기 전 까지 초기화가 안되는 특징이 있다.

 

따라서, 체크때마다 true / false를 반복해서 반환하는 이슈가 발생

728x90
반응형
728x90
// < 18
type TagPrpos = {
  name: string,
};

const Tag: React.FC<TagProps> = ({ name }) => (
  <div>
    <div>{ name }</div>
    { children }
  </div>
);
// > 18
type TagPrpos = {
  name: string,
  children: react.ReactNode
};

const Tag: React.FC<TagProps> = ({ name, children }) => (
  <div>
    <div>{ name }</div>
    { children }
  </div>
);

 

children 요소를 명시적으로 선언해줘야한다.

< 18에서는 children이 optional로 선언되어있었던 반면,

18에서는 optional 선언도 제거되었기 때문이다.

728x90
반응형
728x90

class변수를 어떤 방식으로 선언할지 고민해보게되는 계기가 있었다.

class변수에는 총 세가지가 있다
1. static 변수
2. instance 변수
3. local 변수

각각의 특성에 대해 알아보고 언제 어떻게 선언하는게 프로그램에 도움이 되는지 고민해보자.

1. static변수

class HumanLifeCycle {
  static morningRoutine = 'coffee';
  ...
}

위에서 보이는 static키워드를 이용한 선언 방식이 static변수이다. 변수를 static으로 선언하게 되면 해당 클래스러 몇개의 인스턴스를 생성하던지 상관없이 메모리상 하나의 변수만 참조하게된다. 따라서, 메모리를 절약할수 있다는 장점이 있다.
그렇다고 늘 static으로 선언해서는 안된다. 단 하나의 변수라는 개념인 만큼 여러 인스턴스에서 하나의 값을 공유하게 되기 때문에 각 인스턴스가 독립적으로 변수를 다뤄야 한다면 static을 써서는 안된다.
static이란 이름에 걸맞게 정적이고(변동이 없고) 클래스 인스턴스 간 글로벌하게 쓰이는 경우에 static변수를 쓰도록 하면 어떨까?

2. instance변수

class HumanLifeCycle {
  constructor() {
    this.pattern = {
      morning: '',
      afternoon: '',
    };
  }
}

위 코드에서 보이는 this.pattern이 instance변수에 해당한다. new연산자를 통해 인스턴스를 생성할때 마다 메모리에 해당 변수에 대한 공간을 할당한다. 즉, 인스턴스간 독립적인 변수를 갖게된다.
static이 클래스 레벨에서 변수를 공유하는것과 달리 인스턴스 레벨에서 변수를 다룬다는 차이가 있다. 메모리에 예민한 프로그램이 아니라면 직관적인 instance변수를 주로 즐겨쓰지만 최고의 프로그래머가 되려면 최적화에 대해 더 고민해볼 필요가 있을것 같다.

3. local변수
클래스 내 메소드에서 선언한 변수에 해당한다. 메소드 내에서 잠시 값을 담아두기 위해 쓰이곤 한다.

728x90
반응형
728x90

1. tsc 컴파일시 디렉토리 생성 기준
-> 최상위에 위치한 ts파일

2. 컴파일된 js파일이 위치할 폴더 지정
-> outDir

3. 컴파일할 폴더의 루트경로 설정 (해당 설정을하면 경로외에 위치한 ts파일이 있을때 컴파일 에러를 발생 시킨다. 협업시 잘못된 디렉토리 구조 생성을 방지할 수 있다.)
-> rootDir

4. 컴파일 대상에서 특정 파일 제외
-> exclude (배열에 경로+파일명으로 지정, *사용가능)

5. 컴파일 대상 제한 (징정된 파일만 컴파일함)
-> include (배열에 경로+파일명으로 지정, *사용가능)

6. 업데이트 된 ts파일만 컴파일 (true로 하면 디스크 공간을 더 많이 차지한다는 이슈..? 가 존재)
-> incremental

7. 컴파일 수준 정의 (보통 es5/6), 낮은 버전을 쓸수록 더 더러운 코드가 많이 발생하기 때문에 적정 수준의 버전 선택이 중요함
-> target

8. 모듈 정보를 어떤 것으로 할지 설정 (node 환경이면 보통 commonjs, 브라우저 환경이면 ecmascript에 맞는것으로)
-> module

9. module에서 필요한 library만 설정하려면
-> lib (배열에 지정, dom 등이 위치할 수 있음)

10. 프로젝트에 js를 쓸것을 허용
-> allowjs

11. js파일에서 문제가 있다면 경고를 띄움
-> checkjs

12. react관련 jsx를 쓰려면
-> jsx

13. 내 코드를 라이브러리로 공유, 타인에게 제공할 계획이라면..?
-> declaration

14. 다수의 컴파일된 js파일을 하나의 파일로 만드려면
-> outfile

15. incremental과 함께 이전 빌드 정보를 기억해, 다음 빌드 속도를 향상시키려면
-> composite

16. incremental을 사용할때 이전 빌드 정보를 저장할 파일 경로를 지정하려면
-> tsBuildInfoFile

16. 코드상에 comment를 모두 제거하려면
-> removeComment

17. 컴파일 에러체크만 하고 js로의 컴파일로 변경은 하고싶지 않을때
-> noEmit

18. 각각의 파일을 다른 모듈로 변환하고자 할때
-> isolatedModules

19. 엄격한 확인을 굳이굳이 특별한 이유로 받기 싫다면
-> strict false

728x90
반응형
728x90

제네릭
보기에도 이상하고 워딩도 애매서
단어만 들었을땐 거부감이 좀 든다

하지만, any를 남발하지 않으려면
제네릭은 반드시 알아야만 할것으로 생각된다.

분명 많은 개발자들이 any를 쓰는 그 순간까지
아 이거 그런거 없나..
하고 생각했을텐대
알고보면 바로 그게 제네릭이다
(나만 그랬나..?)

제네릭에대해 바로 알아보자.
제네릭을 정의 하자면 "아직은 정해지지 않았지만 쓰는 사람이 쓰는 타입에 따라 유동성있게 정해지는 타입임"을 의미한다.

일단, 제네릭 없이 각 기계장치에 엔진을 간단 붙여본다.

interface Vehicle {
  run() => void;
}

class Car implements Vehicle {
  run(runTime: number) {
    console.log('4 wheels drive...', runTime);
  }
  
  changeWheel(wheelNumber: number) {
    if (wheelNumber > 4)
      throw new Error('You have only 4 wheels...');
      
    console.log('changed whleel');
  }
}

class Airplane implements Vehicle {
  run(runTime: number) {
    console.log('2 wings drive...', runTime);
  }
  
  fixWing(wingPosition: 'left' | 'right') {
    console.log('fix..!');
  }
}

function doPreRun(vehicle: Vehicle): Vehicle {
  vehicle.run(30);
  return vehicle;
}

const genesis = new Car();
genesis.changeWheel(3); // ok

doPreRun(genesis);
genesis.changeWheel(4); // failed error

위 코드에서 보다시피
예열이 되어 반환된 인스턴스는
본인의 정체성을 잃고 interface의 구현만 갖는다.
doPreRun함수가 Vehicle 인스턴스를 리턴하기 때문이다.

이러한 상황을 피하고 보다 유동성있고 추상화하여 작성하고 싶다?
이럴때 바로 제네릭이 필요하다
제네릭을 이용해 코드를 작성해본다.

function doPreRun<T>(vehicle: T): T {
  vehicle.run(30);
  return vehicle;
}

const genesis = new Car();
genesis.changeWheel(3); // ok

doPreRun(genesis);
genesis.changeWheel(4); // ok

T라는 캐릭터를 썻는데 어려워할 필요없다.
임의의 T(Type)이라는 것이니까
다른 표현으로 V(Value), K(Key) 등이 많이 쓰인다고한다.


조금만 더 나아가보자.
지금은 T라는 타입이 너무 광번위 하여
다른 개발자가 Vehicle이 아닌 인스턴스를 넘길 위험이 존재해 보인다.

function doPreRun<T extends Vehicle>(vehicle: T): T {
  vehicle.run(30);
  return vehicle;
}

const genesis = new Car();
genesis.changeWheel(3); // ok

doPreRun(genesis);
genesis.changeWheel(4); // ok

이렇게
Vehicle을 확장(상속)하여 구현한 타입만을
허용하도록 수정할 수 있다.

제네릭을 더욱 유용하게 쓰기위해
constrains라는 것에 대해 알아볼것이다.
constrains는 제네릭에 조건을 거는것이다

const obj1 = {
  name: 'mocar',
  age: 31,
};

const obj2 = {
  hasPen: true,
  hasNote: false,
};

const obj3 = {
  cash: 3000,
  debt: 1000000,
};

const getValue<T, K extends keyof T> = (obj: T, key: K): T[K] => {
  return obj[key];
}

어떤가
알고보면 그렇게 어렵지않고
매우 유용한것이다.

728x90
반응형

'개발, 코딩 > typescript' 카테고리의 다른 글

Typescript, "people.name!" - what is meaning?  (0) 2023.06.05
optional과 undefined의 차이  (0) 2022.10.26
typescript, 타입 소개  (0) 2022.10.26
728x90

함수형 프로그래밍, 방어적 프로그래밍 등

다양한 영역에 걸쳐서

순수함수를 작성할 것을 강조한다.

 

순수함수란 무엇인가?

const total = sum(2, 8);

function sum(a, b) {
  return a + b;
}

여기 sum이라는 함수처럼

부수효과가 없는 함수 

즉, 어떤 함수에 동일한 인자를 주었을 때 항상 같은 값을 리턴하는 함수

 

부수효과?

그것의 의미는 바로,

외부의 상태를 변경하는 것

또는 함수로 들어온 인자의 상태를 직접 변경하는 것

을 의미한다.

 

순수함수가 아닌 경우의 sum

const total = sum(2, 8);
let favoriteNumber = 4;

function bugSum(a, b) {
 const sum = a + b;
 favoriteNumber = sum;
 return sum + favoriteNubmer;
}

 

위와 같이 함수를 작성하면

언제 프로그래밍에 버그를 만들어낼지 모른다.

나 혼자 개발한다면

혼자 잘 주의해서 개발하면 괜찮지만

 

다른 개발자가

내 코드를 받아서 사용할때

부수효과를 만들수 있는 favoriteNumber를

직접 조작하는 경우 등

에러요인이 만들어 질 가능성이 존재한다.

 

순수함수를 작성하도록 노력하자!

728x90
반응형

'개발, 코딩' 카테고리의 다른 글

객체지향 프로그래밍 핵심 개념  (0) 2022.10.27
git 기본기_백과사전(2)  (0) 2022.10.26
git 기본기_백과사전 (1)  (0) 2022.10.24
git 협업하기 - 실무편  (0) 2022.10.23
Webpack 구성 이해하기  (0) 2022.10.04
728x90

명령형, 절차지향적 프로그래밍

앱을 구현하기위한 데이터와 함수로 구성됨
정의된 순서대로 함수가 구동하는 프로그래밍
구현을 위해서는 모든 코드를 이해해야하여
유지보수가 어렵고 에러찾기가 어렵다.


객체지향 프로그래밍

서로 관련있는 데이터와 함수를
여러가지 오브젝트(객체)로 구성하여
프로그래밍 해나가는 것.
문제가 생기면 관련된 오브젝트만 확인하면 되고,
기능을 추가한다면 새로운 오브젝트를 만들면 되어
유지보수가 쉬워진다.


오브젝트(객체)

데이터와 함수로 구성됨
하나의 객체로써 명사로 이름을 짓는다.
오브젝트 내 데이터는 fields/properties라고 부른다.
오브젝트 내 함수는 메소드라고 부른다.


클래스와 오브젝트

클래스는 오브젝트를 만드는 일종의 템플릿
템플릿(클래스)를 이용해 만든 객체가 오브젝트
이러한 객체를 클래스의 인스턴스라고 부른다.


객체지향 프로그래밍의 원칙

캡슐화 / 추상화 / 상속 / 다형성 이 4가지를
객체지향 프로그래밍의 4원칙 이라고 부른다.


캡슐화

여러 기능들 중 서로 연관성있는 기능들을
묶는것을 "캡슐화"

eg)
감기약 캡슐에 다양한 성분의 약이 있지만
캡슐로 감싸두고, 안에 무엇이 있는지 모르고 그냥 먹는것과 같음

eg)
우리가 고양이 내부의 상태를 직접 바꿀수 없다.
고양이와 놀아줌으로써 내부 상태를 바꿀수는 있다.

이렇듯 안에 있는 것은 직접 건드리지 않고,
외부에 공개된 기능을 통해 내부의 값을 변경하는 것
그리고 어떤것을 외부에 공개하고 공개 안할지 결정하는것

이러한 일련의 행위를 "캡슐화" 라고함
키워드: public / private / protected

멤버변수의 기본 상태: public
외부에 공개하고 싶지 않을때: private
외부에서는 접근 할수없지만 상속한 자식 클래스에서는 접근할수있게 해주는것: protected

추상화

내부의 복잡한 기능을 다 이해하지 않더라도
외부에서 내부가 어떻게 구현됐는지는 상관않고
외부에서 보이는 인터페이스 만으로 이용할 수 있는 것 다시 말하면,
우리가 자동차의 원리를 몰라도 엑셀과 브레이크만 알면 운전할수 있듯이 외부에서는 내부에 어떻게 구현됐는지 신경쓰지않고 인터페이스만을 통해 함수를 이용할 수 있도록 하는 것

추상화 전

type Animal = 'dog', 'cat', 'pig';
type PetSkill = 'give me hand', 'sit down', 'high five';

class Pet {
  private skills: PetSkill;
  
  cosntructor(public kind: Animal, public name: string) {
  }
  
  training(skill: PetSkill) {
    this.edu();
    this.charming();
    this.skills.push(skill);
  }
  
  charming() {
    ...
  }
  
  edu() {
    ...
  }
}



추상화 방법1 - 정보은닉

type Animal = 'dog', 'cat', 'pig';
type PetSkill = 'give me hand', 'sit down', 'high five';

class Pet {
  private skills: PetSkill;
  
  cosntructor(public kind: Animal, public name: string) {
  }
  
  training(skill: PetSkill) {
    this.edu();
    this.charming();
    this.skills.push(skill);
  }
  
  private charming() {
    ...
  }
  
  private edu() {
    ...
  }
}

const myPuppy = new Pet('dog', 'meongu');
myPuppy.training('give me hand');



추상화 방법2 - interface

type Animal = 'dog', 'cat', 'pig';
type PetSkill = 'give me hand', 'sit down', 'high five';

interface Pet {
  training(skill: PetSkill): void;
}

class FriendPet {
  private skills: PetSkill;
  
  cosntructor(public kind: Animal, public name: string) {
  }
  
  training(skill: PetSkill) {
    this.edu();
    this.charming();
    this.skills.push(skill);
  }
  
  charming() {
    ...
  }
  
  edu() {
    ...
  }
}

const myPuppy: Pet= new FriendPet('dog', 'meongu');
myPuppy.training('give me hand');



상속

상속을 이용하면 잘 정의해둔 클래스를 재사용하여 부모 클래스의 function, properties를 상속하여 새로운 클래스를 쉽게 만들어 낼 수있다.


다형성

상속을 받은 자식 클래스들은 자신이 무엇인지와 관계없이 부모 클래스의 function을 공통적으로 호출할 수 있다.

static

모든 인스턴스가 동일하게 가지는 멤버변수가 있다면 static을 붙여주자. 그러면 class레벨로 멤버변수가 변경되어, 매번 인스턴스를 만들때마다 메모리를 차지하지 않는다.

get/set

getter, setter를 활용하면
클래스 사용자는 멤버변수를 다루듯이
age를 쓸수있으면서, 내부적으로는 예외처리까지 할수있다.
이러한 큰 장점이 있어 많은 개발자들이 애용하고있다.
(어떤 개발자는 getter/setter가 몇몇 경우에 직관적이지 못하다 등의 이유로 쓰지 않는것을 권장하기도 한다.)

class Person {
  private nationalAge: number;
  constructor(private firstname: string, public lastname: string) {
  }
  
  get fullname(): string {
    return `${this.firstname}${this.lastname}`;
  }
  
  get age(): number {
    return age;
  }
  
  set age(num: number) {
    if (!num || typeof num !== number) {
      throw new Error('숫자를 넘기셔야지요!');
    }
    
    this.nationalAge = num;
  }
}

728x90
반응형

'개발, 코딩' 카테고리의 다른 글

순수함수 (pure function)  (0) 2022.11.06
git 기본기_백과사전(2)  (0) 2022.10.26
git 기본기_백과사전 (1)  (0) 2022.10.24
git 협업하기 - 실무편  (0) 2022.10.23
Webpack 구성 이해하기  (0) 2022.10.04
728x90

1. optional

function getName(first: string, last?: string): string {
  return first + last;
}

getName('lee'); // ok
getName('lee', undefined); // ok
getName('lee', 'webster'); // ok

 

2. undefined

function getName(first: string, last: string | undefined): string {
  return first + last;
}

getName('lee'); // error
getName('lee', undefined); // ok
getName('lee', 'webster'); // ok

 

위의 예시로 보아 알수있듯이

optional을 쓰지않고 undefined 를 쓰게되면

명시적으로 undefined로 선언해주어야만 한다.

728x90
반응형
728x90

1. string

문자열 타입

 

2. number

숫자

 

3. booelan

true/false

 

4. undefined

데이터 타입이 있는지 없는지 알수없는 경우에 주로 쓰이며

단독으로 쓰이기 보다는

string | undefined와 같이 쓰인다.

(| 는 유니온 타입으로 A타입 또는 B타입 처럼, 타입을 또는 이라는 키워드로 묶어준다.)

 

5. null

undefined과 유사하지만

값이 있는지 없는지에 대한것

주로, string | null 형태로 쓰인다

 

6. unknown 💩

any와 마찬가지로 어떤 type이든 올수있다.

무엇이 올지 알수없을때 사용되는데,

사실 typescript에서는 사용되지는 않고

javascript와 혼합해서 코드를 작성할때

무엇이 return되는지 알수없거나 할 때 사용한다.

 

7. any 💩

무엇이든, 어떤것이든 할당할 수 있는 타입이다.

정말 불가피한 경우에 도피처로 사용된다.

 

8. void

함수가 동작은 하지만

return이 없는 함수인 경우 혹은 return; 인 경우

void type에 해당한다.

 

9. never

함수에서 while: true, throw error와 같이

앱이 죽을 정도로 절대로 리턴이 발생할 수 없는 경우의

타입에 해당한다.

 

10. object 💩

어떤 타입의 object(객체)라도 받을 수 있는 타입이다.

심지어 배열도 가능하다.

 

11. Promise

함수에서 promise를 return하는 경우 사용되며

주로 Promise<number>와 같이

리턴되는 데이터를 제네릭으로 갖는다.

 

12. array

string[] 또는 Array<string>으로 정의할 수 있다.

readonly를 부여해서 수정 불가능하게 만들수도 있다.

const numbers: readonly number[] = [1,2,3];

function sum(numbers: readonly number[]) {
...
}

 

13. Tuple 💩

배열과 비슷하지만 각 자리에 오는 값의 타입을 정할 수 있다.

const items: [string, number] = ['pen', 100];

 

14. type alias

타입을 직접 정의하는것

type device = {
  laptop: string;
  phone: 'iphone' | 'galaxy';
};

 

15. String Literal

위에 alias타입에서 슬쩍 나온 부분이다.

type OS = 'ios';
const myPhone: OS = 'galaxy'; // error
const myPhone: OS = 'ios'; // ok

지정된 문자열 값만 허용하는 타입이나

 

16. union

위에서도 몇번 나왔지만

union타입이란 

A 또는 B 또는 C ... 와 같이

몇개의 타입중에 하나에 해당하는 것이라고 정의할 때 쓰인다.

type OS = 'linux' | 'macos' | 'window';

 

17. Discriminated union

alias와 union타입을 적절하게 이용하면,

보다 나은 개발을 할 수 있다.

type SUCCESS_RESPONSE = {
  result: 'success';
  body: {
    code: string;
    data: string;
  };
};

type FAILED_RESPONSE = {
  result: 'failed';
  reason: string;
};

type API_REPSONSE = SUCCESS_RESPONSE | FAILED_RESPONSE;

// res.result 자동완성 가능
function requestSomething(res: API_RESPONSE) {
  if (res.result === 'success') {
  } else {
  }
}

 

18. intersection

union이 or과 같다면

intersection은 and와 같다.

A타입 이면서 B타입인 경우에 사용한다.

type desk = {
  material: string;
  size: number;
};

type table = {
  color: string;
  height: number;
};

const multiDesk: desk & table = {
  material: '',
  size: 1200,
  color: 'white',
  height: 600,
};

 

19. Enum 💩

여러가지 관련된 상수를 정의할때 사용한다.

// js
const DAYS = Object.freeze({
  "MONDAY": 1,
  "TUESDAY": 2,
});

//ts - enum에 값을 지정하지 않으면 맨 위부터 0으로 초기화됨
enum DAYS {
  Monday,
  Tuesday
};

enum REST {
  POST = 'POST',
  GET = 'GET',
};

enum으로 타입을 설정했더라도

다른 값으로 값을 초기화 할수 있다는 이슈가 있다.

즉 타입이 보장되지 않는다.

const yesterday: DAYS = 1; // ok
const today: DAYS = 10; // ok..?

위와 같은 경우에는

유니온 타입으로 타입을 정의하는게 더 바람직하다.

 

20. type assertion 💩

타입에 대해 완전히 확신할때 타입을 강제로 캐스팅하여

타입의 메소드를 사용할 수 있다.

 

typescript에서는 거의 쓰이지 않지만

js코드와 병행해서 작업할때 종종 쓰일 수 있다.

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

const result = sum(1, 5);
(result as string).length; // undefined
(result as Array<number>).length // app crahsed
result!.length; // app crahsed, 완전히 타입에 대해 확신할때 !를 사용하여 warning을 제거할 수 있다

 

728x90
반응형