본문 바로가기
Angular/Angular Developer Roadmap

TypeScript에서 any는 정체가 뭘까?

by chief_sac 2021. 10. 22.
반응형

Any == Object == {} , Any == Generic? 타입스크립트를 접하면서 겪게되는 궁금증이었습니다. 분명히 "타입"스크립트 타입이라고 언어의 이름에도 붙어있을정도로 타입을 중요시하는 언어가 구상타입에 의존하게 만들어서 에러를 발생하게 할지도 모르는 any를 만들었을까. 이는 너무 편리하면서도 예상하기 힘든 에러를 발생할 지모르는 양날의 검이라고 생각하여 조금더 정확하게 공부하기위해 찾아보게되었습니다.

 

 

let anyType: any;
let objType: Object;
let parenthesis : {};
  • 타입스크립트를 사용하다보면 가장 자주 마주치게 되는 any라는 타입에 대한 이야기를 해보고자 합니다.
  • 위에 작성한 코드를 보았을때 어떤 차이를 갖는지 typeScript는 어쩌다 any를 만들었는지에대하여 고민해보고 공부 해 보았습니다.

 

먼저 처음으로 위 3가지 타입의 차이를 말하자면

  • anyType의 경우 인터페이스가 없고 무엇이든 될 수 있으며 타입스크립트에서 컴파일러는 해당 멤버변수에대해 아무것도 알수가 없습니다. 그렇기 때문에 멤버모두에 액세스를 할당 하게될때 유형 검사가 수행되지 않습니다. 쉽게말해 컴파일러에게 any라는 자료형은 독립적이고 무시되는 자료형입니다.
  • objType에서는 Object라는 인터페이스가 존재하고 해당 인터페이스에 정의된 멤버만 사용할 수 있다.
  • parenthesis 는 타입스크립트에서 위에서 말한것과 같이 Object를 확장하는데 멤버를 추가하지는 않습니다. 타입스크립트의 경우 타입에대한 호환성은 구조적 서브타이핑을 기반으로 하기때문에 objType과 parenthesis 변수의 객체인터페이스는 동일합니다.

 

여기서 나온결론은 Object와 {}는 같은 타입이다 라는것이 나왔는데 그렇다면 any는 무엇이 다른걸까

그것은 위에서 말한것이 거의 전부와 같습니다.

 

 

  • Object는 인터페이스가 존재하기때문에 컴파일러에게 자신을 무시하라 하는 any보다 제한적입니다.

 

결론은

  • any는 어떤것이든 무엇이든 될 수 있고 Object는 Object클래스의 정의된 함수들과 프로퍼티만 사용 할 수있습니다.

두번째 문제로

 

 

any와 제네릭의 차이


위 내용만이 헷갈릴 수 있는 부분인 것은 아니다.

타입스크립트는 자바와 같이 제네릭이라는 것을 지원하는데 제네릭의 프로그래밍적 정의는

 

제네릭이란 데이터의 타입을 일반화하여 어떠한 형식에 의존하지 않고 하나의 값이 여러 다른 데이터 타입들을 가질 수 있는 것을 의미한다.

 

  • 여기서 말하는 데이터의 타입을 형식에 의존하지 않는다 라는것은 모든것을 허용한다하는 any와 같은 기능이지 않은가 싶고 실제로 사용함에 있어서도 그렇게 까지 큰 차이를 느끼지 못하겠는데 어떠한 차이가 있어 구분을 한 것일까
  • 컴파일러상에서 잡히는것이 없다는것은 동일하다 하지만 런타임에서 다르게 동작한다는 것을 알 수 있다.

 

class AnyandGeneric{
// anylist라는 어떠한 변수도 받을수 있는 any배열
	private anylist: any[] = []; 
	
// anylist에 값을 넣게
	push(val: any): void{
		this.anylist.push(val);
	}

// anylist에서 값을 가져오게하는 함수 
	get(): any {
		return this.anylist.pop();
	}

const anyResult = new AnyandGeneric();

// 정상작동의 경우
anyResult.push('case1,case2,case3');
anyResult.get().split(','); // result = [ 'case1', 'case2' ,'case3' ]   -- not error

//이렇게하면 에러남
anyResult.push(1234);
anyResult.get().split(','); // 숫자형태로 1234를 받아오기때문에 런타임에서 타입 error 발생

}
  • 위의 코드와 같이 일단은 anyResult는 어떠한 데이터든 받아 오지만 그것의 형태를 문맥상 알맞게 바꿔주는것은 아니기 때문에 에러가 난다.

 

  • 이러한 오류를 방지하기위해서 제네릭을 쓰는 것인데 제네릭의 경우 사용되는 방식은 다르다.

 

class AnyandGeneric<T>{ //제네릭 선언, 해당 제네릭에 의해 아래 T로 선언된 변수는 해당 자료형을 갖는다
  private genlist: T[] = [];

  push(val: T): void {
    this.genlist.push(val);
  }

  get(): T {
    return this.genlist.pop();
  }
}

//데이터 형태는 숫자라는걸 이미 알고 거기에 맞춰서 값을 대입해준다.
var typeNumber = new AnyandGeneric<number>();
typeNumber.push(123);
typeNumber.push(456);
typeNumber.get() * 2;  
typeNumber.get() * 2;  

//데이터 형태는 문자
var typeString = new AnyandGeneric<string>();
typeString.push('hello,word');
typeString.push('go,to,home');
typeString.get().split(',');  
typeString.get().split(',');
  • 위의 코드와 같이 타입스크립트에서 제네릭은 클래스를 생성할때 자료형을 지정하여 생성하면 그 자료형에 맞춰서 다형성이 적용된다.

 

여기까지가 제가 공부하고 궁금하여 조사하게된 타입스크립트의 any라는 타입에대한 이야기를 끝내겠습니다!

반응형