코딩애플 Typescript -타입을 파라미터로 입력하는 Generic

김원종·2024년 4월 19일
0

TypeScript 학습

목록 보기
19/28

우리가 함수를 만들때 ( ) 이 부분에 파라미터를 입력한다. 그런데 TS를 사용하면 파라미터로 타입을 입력할수도 있다. < > 이부분에 집어 넣으면 된다. 위 코드가 있을때 a의 타입은 unknown으로 나올것이다. 이유는 x는 unknown으로 지정했기 때문이다. 함수 파라미터를 문법은 변수 만드는 문법과 동일하다. 지금 x를 unknown으로 가득한 array자료로 설정했기 때문에 x는 unknown으로 가득한 array가 나오는것이다.

숫자가 나온다고 숫자로 타입변환 그런것들은 해주지 않는다. 그래서 지금 a는 unknown이라서

이런식으로 + 연산을 하려해도 타입을 모르기 때문에 에러가 발생한다. 해결책은 위 함수에서 narrowing을 하거나 as쓰거나 하면 될것이다. 하지만 이런것들이 조금 불편할것이다.

그럼 Generic 함수를 만들면 된다. 파라미터로 타입을 입력하는 함수이다. 그럼 narrowing이 없어도 타입을 변경할수가 있다.

우선 함수를 만들때 < > 를 쳐주면 된다. 그럼 해당 자리에 파라미터를 넣을수있다. 그 후 해당 함수를 호출하는 곳에서 < > 를 넣어주고 타입을 넣어주면 타입이 지정되는 것이다. 타입을 파라미터로 입력하는 것이다. < > 부분에는 타입만 입력할수가 있다.


이런식으로 다 넣어주면 파라미터로 받은 타입이 다 들어가는것이다. 즉 number라는 타입을 MyTyle에 넣어달라는 뜻이다. 타입은 여러개 넣을수도 있다. 이렇게 하면 narrowing보다 확장성이 조금 있어 보인다.

이런식으로 사용해서 string타입으로도 보낼수가 있다. 하지만 타입을 기입하지 않아도 TS에서는 가끔 자동으로 유추하여 타입을 넣어준다.하지만 자세히 적어주는것이 협업을 할때에도 좋을것이다.

이런 간단한 함수가 있다고 생각해보자. 그런데 함수를 호출하고 타입을 number타입을 넣어주었는데도 에러가 발생한다. 왜냐 x가 아직 불확실하기 때문이다 MyType자리에 string이 들어올수도 있으니 미리 에러로 막아주는 것이다. 그렇다면 narrowing이 필요할것이다.

하지만 이런게 번거로울수도 있다. 그럴때 파라미터를 제한을 할수가있다.extend를 사용해 타입을 지정하는데 MYType이 우측에 있는 타입을 가지고 있는지 체크한다. 여기서 extend는 복사의 개념이 아니라 체크의 개념이라고 생각하자. 일종의 narrowing으로 쳐주기에 가능하다.

우리가 만든 커스텀 타입으로 타입파라미터를 제한할수 있다. 이렇게 코드를 구성하면 string과 array에 length를 사용할수 있기 때문에 에러가 발생한다.

이런 인터페이스가 있다고 가정해보자 length라는 property가 있다고 가정하는 인터페이스 말이다. extends를 사용했기에 오른쪽에 있는 타입을 만족하는지 체크하는것이다. 그런데 number라는 타입에는 length라는 property가 없다 그래서 에러가 발생한다.

그때 string을 넣으면 에러가 발생하지 않는다. length라는 property가 있기때문이다.

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


숙제1) 문자를 집어넣으면 문자의 갯수, array를 집어넣으면 array안의 자료 갯수를 콘솔창에 출력해주는 함수는 어떻게 만들까요?

연습삼아 Generic 이런걸로 만들어봅시다. 굳이 Generic 이런게 필요는 없겠지만요

(동작 예시)
함수('hello') 이렇게 사용하면 콘솔창에 5가 나와야합니다.
함수<string[]>( ['kim', 'park'] ) 이렇게 사용하면 콘솔창에 2가 나와야합니다.

나의 풀이

  interface Check{
    length:number
}

function lengthCheck<T extends Check>(x:T){
    return x.length;
}

let asq= lengthCheck<string>('hello');
let asq1=lengthCheck<string[]>( ['kim', 'park'] );
console.log(asq)
console.log(asq1)

센세 풀이

  function 함수<MyType extends string | string[]>(x: MyType)  { 
      console.log(x.length)   
} 

함수<string>('hello');
함수<string[]>(['kim','park'])
1. <> 안에 타입을 집어넣을 수 있는 함수를 만들었습니다. 그리고 기능은 심플한데 x.length를 출력해줍니다.

2. 근데 에러가 납니다. x에 뭐가 들어올지 모르니까 미리 에러를 내주고 있습니다. 

3. 그래서 <>에 집어넣은 타입은 extends 를 이용해서 string 또는 string[] 얘네들의 특성을 가지고 있는지 확인하라고 했습니다.

그랬더니 x.length 잘 됩니다. 

숙제2) Animal 이라는 타입이 있습니다.

interface Animal {
name : string;
age : number
}

let data = '{"name" : "dog", "age" : 1 }'
그리고 data라는 변수도 있습니다. object처럼 생겼지만 따옴표 쳐진 JSON 자료입니다.

data라는 JSON 자료를 object { } 자료로 변환을 해서 return 해주는 함수를 만들어보십시오.
근데 변환된 object의 타입은 Animal이 되었으면 좋겠는데 어떻게 코드를 짜면 될까요?
오늘 배운 Generic을 이용해서 구현해보도록 합시다.

(동작 예시)

함수(data) 이렇게 쓰면 이 자리에 { name : 'dog' , age : 1 } 이런 object 자료가 남아야합니다. 근데 타입은 Animal임

나의 풀이

  interface Animals {
    name : string;
    age : number
}

let data = '{"name" : "dog", "age" : 1 }'
function AnimalsCheck<T>(data:string):T{
    return JSON.parse(data);
}


let Cj = AnimalsCheck<Animals>(data);

console.log(Cj)

센세 풀이

  interface Animal {
  name : string;
  age : number 
}

let data = '{"name" : "dog", "age" : 1 }';


function 함수(x :string){
  return JSON.parse(x);
}
let result = 함수(data)
console.log(result)
이렇게 하면 JSON --> object 자료 변환기를 만들 수 있습니다.

data라는 변수를 변환한 결과를 출력해보면 근데 타입은 이상한 any 타입입니다. 

그래서 여러분이 Animal 타입을 입력하면 그걸 타입으로 가지라고 직접 지정해주면 되는데 

 

 

interface Animal {
  name : string;
  age : number 
}

let data = '{"name" : "dog", "age" : 1 }';


function 함수<Type>(x :string) :Type {
  return JSON.parse(x);
}
let result = 함수<Animal>(data)
console.log(result)
이렇게 하면 result가 진짜로 Animal 타입을 가지게 됩니다. 

이게 다 타입파라미터 덕분입니다. 

 

Q. as 쓰면 더 쉽지 않나요 return 값 오른쪽에 as Animal 하드코딩 해놓으면 <> 필요없겠네 

A. 들킴

근데 확장성이 없을 수 있습니다. Generic 쓰시면 Animal 말고도 다른 타입으로 변환이 가능하잖아요 

숙제3) class 를 수정해봅시다.

class Person {
  name;
  constructor(a){
    this.name = a;
  }
}
let a = new Person('어쩌구');
a.name //any 타입이 되었넹 

지금 만든 class는 new Person('어쩌구') 라고 분명 문자를 집어넣었는데 any 타입이 name 속성에 부여됩니다.

이게 싫어서 파라미터에 string을 집어넣으면 string 타입

number를 집어넣으면 number 타입

string[]을 집어넣으면 string[] 타입이 되게 하려면 위의 코드를 어떻게 수정해야할까요?

오늘 배운 Generic을 이용해봅시다.

나의 풀이

  class Persosn <T>{
    name;
    constructor(a:T){
        this.name = a;
    }
}
let a = new Person('어쩌구');
a.name //any 타입이 되었넹

센세 풀이

  class Person <T> {
  name;
  constructor(a :T){
    this.name = a;
  }
}
let a = new Person<string>('어쩌구');
a.name //string 타입이 되었넹 
타입파라미터를 입력할 수 있게 만들었습니다.

그럼 이제 new Person 할 때마다 타입 파라미터를 입력할 수 있게 되며

내맘대로 타입지정이 가능합니다.
profile
개린이

0개의 댓글