TypeScript 개념 정리 - 기본 타입

dobby·2025년 6월 3일
0

타입스크립트

목록 보기
1/11
post-thumbnail

Athens 프로젝트를 리팩토링 중이다.
개발 중엔 타입스크립트에 대한 지식은 있지만 활용은 잘 못했기에, 타입 개선 작업을 하고 있다.
거의 다 끝나가서, 공부한 타입스크립트 개념을 정리 해볼까 한다.

타입스크립트에서 제공하는 기본 타입들은 위 사진과 같다.
타입들은 부모와 자식 관계를 맺으면서 계층관계를 형성한다.


원시 타입 (Primitive Type)

하나의 값만 저장하는 타입

number

let num1:number = 123;
let num2:number = Infinity;
let num3:number = -Infinity;
let num4:number = NaN;

string

let str1:string = 'hello';

boolean

let bool1:boolean = true;
let bool2:boolean = false;

null

let null1:null = null;

undefined

let unde1:undefined = undefined;

null 타입이 따로 있기에, null 타입을 추가해주지 않으면 사용할 수 없다.
그래서 null 타입을 지정하지 않더라도 허용하게 해주는 tsconfig 옵션이 있다.
"strictNullChecks": false
: null 타입이 아니더라도 null을 할당할 수 있도록 해주는 옵션 설정

리터럴

변수의 타입을 값 그 자체로 선언한다.
그러면 그 값을 제외한 값은 할당할 수 없다.

let numA:10 = 10;
// numA = 20;

let strA:"hello" = "hello";
// strA = 'haha';
...

배열과 튜플

배열

let numArr:number[] = [1,2,3];
let strArr:string[] = ['hello', 'im', 'sooyeon'];
let boolArr:Array<boolean> = [true, false, true];

// 배열에 들어가는 요소들의 타입이 다양할 경우
let multiArr:(string | number)[] = [1, 'hello'];

// 다차원 배열의 타입을 정의하는 방법
let doubleArr:number[][] = [
	[1,2,3],
	[4,5],
];

튜플

길이와 타입이 고정된 배열

let tup1:[number, number] = [1,2];
// tup1 = [1,2,3];
// tup1 = ['1', '2'];
tup1.push(1);
tup1.pop();

let tup2:[number, string, boolean] = [1, '2', true];

객체

구조를 기준으로 타입을 선언한다.
그래서 타입스크립트를 구조적 타입 시스템이라고 부른다.
property based typeSystem

// 변수가 객체라고만 선언
let uer:object = {
	id: 1,
	name: "황수연",
}

// user.id -> 오류 (object 타입에 id 속성이 없습니다.)
// 객체라고만 정의되고 그 안에 어떤 값들이 있는지는 모르기 때문에 에러가 발생하는 것.

// property를 기반으로 구조적 타입을 선언한다. -> 구조적 타입 시스템
let uer:{
	id?: number; // 옵셔널 프로퍼티 (optional property)
	name: string;
} = {
	id: 1,
	name: "황수연",
}

user.id
user = {
	name: '홍길동',
}

let config: {
	readonly apiKey: string;
} = {
	apiKey: "My API Key",
};

// config.apiKey = "sdfasdf";
// 절대 값이 수정되어서는 안되는 속성이 있다면 readonly 키워드를 붙여준다.

구조적 타입 시스템의 반대인 명목적 타입 시스템은 이름으로 타입을 선언하는 것을 말한다.

구조적 타입 시스템
객체나 인터페이스의 구조가 동일하다면 해당 객체나 인터페이스가 같은 타입이라고 간주하는 타입 시스템이다. 즉, 객체의 내부 구조가 동일하면 서로 다른 소스에서 나왔더라도 같은 타입으로 간주된다.

명목적 타입 시스템
변수나 객체의 타입이 이름(명칭)에 의해 결정되는 타입 시스템이다. 구조적으로 동일한 구조를 가지더라도 명시적인 명칭이 같아야만 두 객체가 같은 타입으로 간주된다.


타입 별칭과 인덱스 시그니처

타입 별칭

타입 선언이 많아지게 되는 경우 타입을 변수처럼 사용하면 된다.
자바스크립트로 변환될 때 타입에 대한 코드들은 삭제된다.
즉, 타입 별칭에 대한 내용도 사라진다.

type User = {
	id: number;
	name: string;
	nickname: string;
	birth: string;
	bio: string;
	location: string;
};

let user: User = {
	id: 1,
	...
}

let user2: User = {
	id: 2,
	...
}

인덱스 시그니처

key와 value의 규칙을 기준으로 객체의 타입을 정의할 수 있는 문법

인덱스 시그니처 타입은 해당 규칙을 위반하지만 않으면 모든 객체를 허용하는 타입이다.
즉, 객체 내에 속성이 없어도 허용된다.

type CountryCodes = {
	[key: string]: string
}

let countryCodes: CountryCodes = {
	korea: 'ko',
	unitedState: 'us',
	unitedKingdom: 'uk',
	...
}

type countryNumberCodes = {
	[key: string]: number;
	korea: number;
}

let countryNumberCodes = {
	korea: 410, // 꼭 작성해주어야 한다.
	unitedState: 840,
	unitedKingdom: 826,
}

Enum 타입 (열거형 타입)

여러가지 값들에 각각 이름을 부여해 열거해두고 사용하는 타입
자바스크립트에는 없고, 타입스크립트에만 있는 문법이다.

프로젝트 리팩토링 할 때, 타입으로도, 값으로도 사용할 수 있어 아주 유용하게 사용한 타입이다.

enum Role {
	ADMINN, // 0
	USER, // 1
	GUEST = 2,
} // 숫자형 이넘

enum Language {
	KOREAN = 'ko',
	ENGLISH = 'en',
}

const user1 = {
	name: "황수연",
	role: Role.ADMIN // 0
	language: Language.KOREAN,
}

타입스크립트의 enum은 컴파일 결과 사라지지 않는다.
객체 형식으로 바뀌어 변환된다.

enum Provider {
  KAKAO = 'kakao',
  GOOGLE = 'google',
}

const getRedirectUri = (provider: Provider) => {
  ...
};
  
return (
  <>
  	<Link
  	  href={getRedirectUri(Provider.KAKAO)}
  	>
  ...
  </>
)

위의 코드처럼 타입으로도, 값으로도 사용할 수 있다.


Any와 Unknown 타입

Any

특정 변수의 타입을 확실히 모를 때 사용한다.

let anyVar:any = 10;
anyVar = 'hello' // 나중에는 문자열도 들어가야 할 때
anyVar = true;
anyVar = {};
anyVar = () => {};

// 메소드도 사용 가능
anyVar.toUpperCase();
anyVar.toFixed();

// 다른 변수에 할당도 가능
let num:number = 10;
num = anyVar;

컴파일하면 오류가 발생한다.
이는 함수에서 toUpperCase를 실행하려고 해서 오류가 발생한 것으로, 타입스크립트가 가지는 이점을 포기하는 타입이라고 보면 된다.

그렇기에 가능한 사용하지 않는 것이 좋다.

Unknown

any 타입과 똑같이 어느 타입이든 들어갈 수 있다.

let num:number = 10;
num = anyVar;

let unknownVar:unknown;
unknownVar = "";
unknownVar = 1;
unknownVar = () => {};

// num = unknownVar; 안된다.
// unknownVar.toUpperCase(); 안된다.

if(typeof unknownVar === 'number' {
	num = unkownVar;
}

any와 unknown의 차이

  • unknown은 any 타입 외의 어떤 타입에도 할당할 수 없다.

  • 또한, unknown 타입은 여러 타입의 메소드를 사용할 수 없다.
    할당 혹은 메소드를 사용하려면 typeof로 타입을 조건문으로 알아내어 사용해주어야 한다.

  • 반면 any는 never를 제외한 모든 것에 할당 가능하다.


Never와 Void 타입

void

아무것도 없음을 의미하는 타입이다.

function func1():string {
	return 'hello';
}

function func2():void {
	console.log('hello');
}

function func3():undefined {
	console.log('hello');
	return undefined // return;
}

let a:void;
// a = 1;
// a = 'hello';
// a = {};
a = undefined;

Never

존재하지 않는, 불가능한 타입이라는 의미이다.

// 함수의 반환 타입이 존재하는 것 자체가 모순인 경우
function func4():never {
	while(true) {};
}

// 실행되면 바로 프로그램이 중지되지 때문에 never가 적합
function func5():never {
	return new Error()
}

let a = never;
// a = 1;
// a = {};
// a = "";
// a = undefined;
// a = null; // 옵션이 false여도 담을 수 없다.
// any 타입의 값도 저장할 수 없다.
profile
성장통을 겪고 있습니다.

0개의 댓글