Notice
Recent Posts
Recent Comments
Link
«   2025/01   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
Tags
more
Archives
Today
Total
관리 메뉴

ksw_devlog

TIL 12주 3일차- Type script 본문

TIL

TIL 12주 3일차- Type script

kimcoach 2023. 1. 18. 20:52
function 내함수(x :number | string){
   return x + 1  //에러남 
}

 

 

Operator '+' cannot be applied to types 'string | number' and 'number'

string | number 같은 union type 에는 일반적으로 조작을 못하게 막아놔서 그렇습니다. 

이런 메세지를 보면 1. 타입을 하나로 Narrowing 해주거나 2. Assert 해주거나 둘 중 하나 해주면 됩니다. 

 

 

Type Narrowing 

 

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

그래서 아까 함수를 사용할 때

 

function 내함수(x :number | string){
  if (typeof x === 'number') {
    return x + 1
  } 
  else if (typeof x === 'string') {
    return x + 1
  }
  else {
    return 0
  }
}

 

 

if문과 typeof 키워드로 현재 파라미터의 타입을 검사해서 

"이게 'number' 타입일 경우 이렇게 해주세요~"

"이게 'string' 타입일 경우 이렇게 해주세요~"

이렇게 코드를 짜야 정상적으로 사용이 가능합니다. 

타입스크립트는 타입 애매한걸 싫어해서 귀찮아도 하셔야함 

타입이 확실하지 않을 때 생기는 부작용을 막기위한 장치라고 보시면 되겠습니다. 

가끔 이걸 "defensive 하게 코딩한다"라고 하기도 합니다.

 

 

근데 또 함수 안에서 if문 쓸 때는 마지막에 else {} 이거 없으면 에러가 납니다.

return 하지않는 조건문이 있다면 나중에 버그가 생길 수 있어서 에러를 내주는 것인데 

"noImplicitReturns": false, 

이게 성가시다면 tsconfig.js 파일에서 이걸 추가하면 됩니다. 근데 굳이 수정하는 것 보다는 엄격하게 씁시다. 

 

 

- 꼭 typeof를 쓸 필요는 없고 타입을 하나로 확정지을 수 있는 코드라면 어떤 것도 Narrowing 역할을 할 수 있습니다. 

- in, instanceof 키워드도 사용가능합니다.

 

Type Assertion

 

아니면 타입을 간편하게 assert 할 수도 있습니다. 

"이 변수의 타입을 number로 생각해주세요"

이런 뜻으로 코드를 짜면 타입스크립트 컴파일러가 눈감아줍니다. 

변수명 as string

이런 식으로 as라는 키워드 쓰면 됩니다. 

 

function 내함수(x :number | string){ 
    return (x as number) + 1 
}
console.log( 내함수(123) )

변수명 as number 라고 쓰시면

"나는 이 변수를 number라고 주장하겠습니다~" 라는 뜻이며 실제로 그렇게 타입을 변경해줍니다.

아무튼 이렇게 타입스크립트 컴파일러에게 반기를 들 수 있습니다. 

근데 이러려면 내가 "함수에 무조건 숫자가 들어올 것이다"라는 사실을 알고 있어야 안전하게 쓸 수 있는 문법이겠죠?

 

 

as 키워드 사용시 특징이 있는데 

1. as 키워드는 union type 같은 복잡한 타입을 하나의 정확한 타입으로 줄이는 역할을 수행합니다. (number 타입을 as string 이렇게 바꾸려고 하면 에러날걸요)

2. 실은 그냥 타입실드 임시 해제용입니다. 실제 코드 실행결과는 as 있을 때나 없을 때나 거의 동일합니다.

아무튼 그러면 이제 변수를 숫자로 가정해서 가공할 수 있습니다.

 

 

 

Q. 근데 내함수('123') 이렇게 숫자말고 문자를 입력하면 어떻게 됩니까

A. as number라고 썼긴 했지만 number 타입처럼 +1 해주진 않습니다. 콘솔창에 결과 출력해보면 '1231' 이렇게 출력될걸요

as는 그냥 주장만 하는거지 실제로 타입을 바꿔주는건 아니기 때문입니다. 

 

 

 

as 쓰면 간편해쥬금 하지만 정확히 코드짜려면 narrowing을 씁시다.  

as 키워드는 맘대로 타입을 개발자 맘대로 주장하는 역할이라 때문에 엄격한 타입체크기능을 잠깐 안쓰겠다는 뜻과 동일합니다.

그래서 as 문법은 이럴 때 쓰도록 합시다.

1. 왜 타입에러가 나는지 정말 모르겠는 상황에 임시로 에러해결용으로 사용하거나

2. 내가 어떤 타입이 들어올지 정말 확실하게 알고 있는데 컴파일러 에러가 방해할 때

알겠죠? 뉴비처럼 온갖군데 as 키워드 붙이면 안됩니다. 

물론 대부분의 상황에선 as 보다 훨씬 엄격하고 좋은 type narrowing으로 해결할 수 있습니다.

 


 

타입 정의가 너무 길면 Type Aliases (별칭)

 

let 동물 :string | number | undefined;

매우 길고 복잡하게 타입을 나열하는 경우가 많습니다. 

1. 이게 길고 보기싫으면

2. 나중에 또 사용하고 싶으면

변수에 담아쓰십시오. 

변수만드는 것 처럼 type 이라는 키워드를 쓰면 됩니다. 

type 키워드 쓰는걸 type alias 라고 합니다.

alias를 번역하자면 별칭인데 저는 그냥 쉽게 변수라고 부르겠습니다. 

 

 

type Animal = string | number | undefined;
let 동물 :Animal;

type 타입변수명 = 타입종류

타입을 변수처럼 만들어서 쓰는 alias 문법입니다. 관습적으로 대문자로 시작합니다. 

일반 자바스크립트 변수랑 차별을 두기 위해 AnimalType 이런 식으로 작명하는게 어떨까요.

 

object 타입도 저장가능합니다

 

type 사람 = {
  name : string,
  age : number,
}

let teacher :사람 = { name : 'john', age : 20 } 

 

속성 몇개가 선택사항이라면 

 

그니까 어떤 object자료는 color, width 속성이 둘다 필요하지만

어떤 object 자료는 color 속성이 선택사항이라면 

type alias를 여러개 만들어야하는게 아니라 물음표연산자만 추가하면 됩니다.

 

type Square = {
  color? : string,
  width : number,
}

let 네모2 :Square = { 
  width : 100 
}

Square라는 type alias를 적용한 object 자료를 하나 만들었습니다.

근데 color 속성이 없어도 에러가 나지 않습니다.

 

실은 물음표는 "undefined 라는 타입도 가질 수 있다~"라는 뜻임을 잘 기억해둡시다.

진짠지 확인하고싶으면 마우스 올려보면 됩니다. 

 

type 키워드 여러개를 합칠 수 있습니다.

 

type Name = string;
type Age = number;
type NewOne = Name | Age; 

OR 연산자를 이용해서 Union type을 만들 수도 있습니다. 

위 코드에서 NewOne 타입에 마우스 올려보시면 string | number라고 나올겁니다. 

 

 

 

type PositionX = { x: number };
type PositionY = { y: number };
type XandY = PositionX & PositionY
let 좌표 :XandY = { x : 1, y : 2 }

object에 지정한 타입의 경우 합치기도 가능합니다. 

& 기호를 쓴다면 object 안의 두개의 속성을 합쳐줍니다. 

위 코드에서 XandY 타입은 { x : number, y : number } 이렇게 정의되어있을 겁니다. 

합치기는 초딩용어고 멋진 개발자말로 extend 한다라고 합니다. 

 

물론 Type alias & Type alias 만 가능한게 아니라 

Type alias & { name : string } 이런 것도 가능합니다. 

 

type 키워드는 재정의가 불가능합니다.

 

type Name = string;
type Name = number;

이러면 에러가 날 겁니다. 

나중에 type 키워드랑 매우 유사한 interface 키워드를 배우게 될텐데

이 키워드를 쓰면 재정의가 가능합니다. 재정의하면 & 하는거랑 똑같은 기능을 하는데

하지만 재정의 불가능한 편이 더 안전하지 않을까요. 

 


Literal Type 만드는 법 

 

string, number 이런 것만 타입이 될 수 있는게 아닙니다.

일반 글자같은 것도 타입이 될 수 있습니다. 

 

let john :'대머리';
let kim :'솔로';

제가 방금 '대머리', '솔로'라는 타입을 만들었습니다.

마음대로 변수나 함수에 할당 가능합니다.

 

그럼 신기하게도 

john이라는 변수는 이제 '대머리' 라는 글자만 할당할 수 있습니다.

kim이라는 변수는 이제 '솔로' 라는 글자만 할당할 수 있습니다. 

특정 글자나 숫자만 가질 수 있게 제한을 두는 타입을 literal type 이라고 부릅니다.

더욱 엄격한 실드라고 보면 되겠군요. 

let 방향: 'left' | 'right';
방향 = 'left';

or 기호 써도 됩니다. 이제 'left' 또는 'right' 글자만 가질 수 있는 변수가 완성되었군요. 

 

function 함수(a : 'hello') : 1 | 0 | -1 {
  return 1 
}

함수도 똑같습니다. 

파라미터 타입선언할 때 글자나 숫자를 집어넣으시면 그 만 파라미터로 넣을 수 있고

return 타입선언할 때도 글자나 숫자를 집어넣으시면 그 값만 return할 수 있습니다.

 

as const 문법

 

'kim' 이라는 타입만 들어올 수 있는 함수를 만들었습니다. 

근데 자료.name을 입력하고 싶은겁니다.

 

var 자료 = {
  name : 'kim'
}

function 내함수(a : 'kim') {

}
내함수(자료.name)

그래서 코드를 이렇게 짜봤는데 위 코드는 에러가 납니다.

 

왜 에러가 나겠습니까. 

함수는 'kim' 타입만 입력할 수 있다고 해놨고 

자료.name 이라는건 string 타입이지 'kim' 타입이 아니기 때문입니다. 

 

 

 

이런걸 해결하고 싶으면

1. object 만들 때 타입을 잘 미리 정하든가 

2. 예전에 배웠던 assertion을 쓰시든가 (as 'kim' 이런걸 붙이는 겁니다)

3. 아니면 as const 라는걸 애초에 object 자료에 붙일 수 있습니다. 

 

var 자료 = {
  name : 'kim'
} as const;

function 내함수(a : 'kim') {

}
내함수(자료.name)

as const는 효과가 2개인데

1. 타입을 object의 value로 바꿔줍니다. (타입을 'kim'으로 바꿔줍니다)

2. object안에 있는 모든 속성을 readonly로 바꿔줍니다 (변경하면 에러나게)

 

object를 잠그고 싶으면 as const를 활용해보도록 합시다. 

 


function type 도 저장가능

 

함수에 들어갈 파라미터와 return으로 뱉을 값들을 타입지정할 수 있다고 배워봤습니다. 

함수 타입도 type alias로 저장해서 쓸 수 있습니다. 

 

 

예를 들어서 1. 숫자 두개를 파라미터로 입력할 수 있고

2. 숫자를 return 하는 함수를 별명을 지어서 사용하려면

type NumOut = (x : number, y : number ) => number ;

이런 식입니다.

 

이걸 함수 만들 때 사용하려면

function 함수이름 :NumOut (){}

이런 식은 불가능합니다. function 키워드에는 () 이거 내부랑 오른쪽에만 타입지정이 가능해서요.

그래서 이렇게 합니다. 

 

type NumOut = (x : number, y : number ) => number 
let ABC :NumOut = function(x,y){
  return x + y
}

함수를 만들 때

let 함수명 = function(){} 이렇게 해도 되니까

함수명 오른쪽에 함수명 : 타입별명

이렇게 지정해서 사용하는 것입니다.

 

methods 안에 타입지정하기 

 

object 자료 안에 함수도 맘대로 집어넣을 수 있습니다. 

몰랐다면 대충 어떻게 생겼는지 알아봅시다.

 

let 회원정보 = {
  name : 'kim',
  age : 30,
  plusOne (x){
    return x + 1
  },
  changeName : () => {
    console.log('안녕')
  }
}
회원정보.plusOne(1);
회원정보.changeName();

plusOne 그리고 changeName 함수를 object 자료에 집어넣었습니다.

arrow function, 일반함수 전부 object 안에 맘대로 집어넣을 수 있습니다. 

넣은 함수들은 똑같이 점찍어서 사용가능합니다. 

type Member = {
  name : string,
  age : number,
  plusOne : ( x :number ) => number,
  changeName : () => void
}

 


html 태그 종류별로 정확한 타입명칭이 있습니다.

a 태그는 HTMLAnchorElement

img 태그는 HTMLImageElement

h4 태그는 HTMLHeadingElement

..

백만개가 있는데 이런 정확한 타입으로 narrowing 해주셔야 html 속성 수정을 제대로할 수 있습니다.

 

타입스크립트에서 쓸 수 있는 HTML 타입들은 이렇게 됩니다.

Element, HTMLElement, HTMLAnchorElement 등이 있는데 

Element에 들어있는걸 복사해서 몇개 더 추가해서 HTMLElement 타입을 만들어놨고

HTMLElement에 들어있는걸 복사해서 몇개 더 추가해서 HTMLAnchorElement 타입을 만들어놨습니다.

 

셀렉터로 대충 찾으면 Element 타입이라는게 부여가 됩니다.

아직 이 태그가 뭔지 몰라서 그냥 광범위한 타입하나를 달랑 지정해주는 겁니다.

이건 광범위한 그냥 일반 html 태그의 특징을 정리해둔 타입이기 때문에 안에 .href .src 이런거 안들어있습니다.

 

반면 HTMLAnchorElement 이건 조금 상세한 타입입니다.

이 타입은 "href, style, class, id 이런 속성을 가질 수 있다~" 라고 타입이 정의되어있습니다.

그래서 a태그에게 어울리는 타입인 HTMLAnchorElement 라는 타입을 쓸 수 있는지 instanceof 키워드로 확인해야합니다. 

확인하는 과정을 narrowing으로 인정해줌 

 


class : 비슷한 object 많이 만들일 있을 때 사용

 

function Test(a) {
    this.q = a;
    this.w = 'asda'
}

new Test('qweqw')

===

class Test {
    constructor(a){
        this.q = a;
        this.w = 'asda';
    }
}

TS : (+ prototype)

 

class Person {
    name :string;
    constructor(a :string){
        this.name = a;
    }
    함수(a : string){
        console.log('hi' + a)
    }
}
Person.prototype.함수('aaaa')

let person1 = new Person('kim');
let person2 = new Person('park');
person1.함수('aaaaqwe')

'TIL' 카테고리의 다른 글

TIL 12주 5일차 - Type script  (0) 2023.01.24
TIL 12주 4일차- Type script  (0) 2023.01.19
TIL 12주 2일차 - Type script 복습  (2) 2023.01.17
TIL 12주 1일차  (1) 2023.01.16
WIL 11주차  (0) 2023.01.16