타입스크립트 기본타입
1. typescript 기본타입
위니브 Typescript 페이지를 이용하여 실습을 진행하겠습니다. 타입스크립트에서 타입은 값이 할당될 때 어떤 타입인지 정해집니다. 이렇게 타입이 지정되어 마우스를 오버해 타입을 알 수 있습니다. 이렇게 타입을 알 수 있다는 것 만으로도 개발에 큰 도움을 받을 수 있습니다.
let value = 'string';
let value = 'string';
이렇게 변수에 값을 할당하면 변수에 타입이 알아서 지정이 됩니다. 타입스크립트에서 변수에 할당된 값을 추론하고 변수에 타입을 할당해 줍니다. 이런 동작을 타입 추론이라고 부릅니다.
1.1 number
number
타입은 모든 숫자를 나타냅니다. 이는 정수 및 부동소수점 숫자를 포함합니다. 무한대를 나타내는 Infinity
, 숫자가 아닌 값을 나타내는 NaN
또한 사용할 수 있습니다.
let decimal: number = 6;
let hex: number = 0xf00d;
let binary: number = 0b1010;
let octal: number = 0o744;
console.log(decimal + decimal);
let decimal: number = 6;
let hex: number = 0xf00d;
let binary: number = 0b1010;
let octal: number = 0o744;
console.log(decimal + decimal);
💡 타 정적 언어에서는 숫자 타입을 float, int 등등으로 세부적으로 구분하기도 합니다. 타입스크립트는 큰 틀에서는 자바스크립트의 타입 구분을 따릅니다.
1.2 string
string 타입은 텍스트 데이터를 나타냅니다. 작은따옴표(') 또는 큰따옴표(")를 사용하여 문자열을 표현할 수 있습니다. 또한 백틱(`)을 사용하여 템플릿 문자열을 표현할 수 있습니다.
let str: string = '문자열';
let str: string = '문자열';
1.3 boolean
boolean
타입은 참(true) 또는 거짓(false) 값을 나타냅니다.
let bool: boolean = true;
let bool: boolean = true;
1.4 bigInt
let bigNum: bigint = 1000n;
let bigNum: bigint = 1000n;
자바스크립트에서 제공되는 가장 큰 수를 넘어가는 수를 사용할 때 필요한 타입입니다. 여기서 일부 에디터에서 경고가 뜰 수 있습니다. 이는 bigint가 ES2020에서 도입된 타입이기 때문입니다. 이 버전보다 낮은 버전을 지원하는 서비스를 사용하고 있다면 이 타입을 사용할 수 없습니다.
1.5 undefined
let value: undefined; // 오직 undefined만 할당 가능
value = undefined; // OK
value = "hello"; // Error
let value: undefined; // 오직 undefined만 할당 가능
value = undefined; // OK
value = "hello"; // Error
let str: string; // 초기값은 undefined이지만 string만 할당 가능
console.log(str); // Error
str = "hello"; // OK
str = undefined; // Error
let str: string; // 초기값은 undefined이지만 string만 할당 가능
console.log(str); // Error
str = "hello"; // OK
str = undefined; // Error
값이 아직 정의되지 않은 상태를 의미하는 undefined
를 할당할 수 있는 타입입니다. 변수를 선언하고 할당하지 않으면 undefined
가 들어있습니다. 이렇게 할당되지 않은 값을 출력하는 것도 애러가 발생합니다.
또한 보통 아래처럼 undefined를 직접 할당하는 경우는 없습니다.
let value: undefined = undefined;
let value: undefined = undefined;
1.6 unknown
unknown
타입의 변수에는 어떤 타입의 값이든 할당할 수 있습니다. 일반적으로 자바스크립트에서 사용되는 변수와 같은 느낌이라고 보시면 됩니다. 주로 일반적인 자바스크립트 라이브러리를 같이 사용할 때, 해당 라이브러리에서 지원하는 메서드의 결과값이 어떤 타입으로 날아오는지 알기 어려울 경우 사용합니다. 타입을 분명하게 지정하는 타입스크립트의 특성과는 거리가 먼, 잘 사용하지 않는 타입입니다.
let notSure: unknown = 4;
notSure = 'maybe a string';
notSure = true;
let notSure: unknown = 4;
notSure = 'maybe a string';
notSure = true;
1.7 any
any
타입도 역시 unknown 과 매우 비슷한 타입으로 어떤 타입의 값이든 할당할 수 있으며, 심지어 존재하지도 않는 속성을 사용할수도 있습니다. 즉 never를 제외한 어떠한 값이든, 어떻게 사용하든 일단 다 허용한다는 의미라고 봐주시면 되겠습니다.
let value: any = 4;
console.log(value);
value = "hello";
console.log(value);
console.log(value.length);
value = [10, 20, 30];
console.log(value);
let value: any = 4;
console.log(value);
value = "hello";
console.log(value);
console.log(value.length);
value = [10, 20, 30];
console.log(value);
💡 unknown과 any 의 차이가 뭔지 잘 모르겠어요.
unknown
타입은 타입스크립트에서 any
의 타입-안전(type-safe) 버전이라고 보면 되겠습니다. any
타입을 사용하면 타입스크립트의 모든 타입 체크를 회피할 수 있어 버그가 발생할 가능성을 높일 수 있는 반면, unknown
타입을 사용하면 타입을 알 수 없는 상황에서도 any
에 비해 더 엄격한 타입 검사를 할 수 있어서 더 안전한 코드를 작성할 수 있습니다.
그 예로 unknown 타입으로 지정된 변수는 반드시 unknown 타입의 변수에 값을 할당할 수 있고,
let vAny: any = 10;
let vUnknown: unknown = 10;
let s1: string = vAny;
let s2: string = vUnknown;
let vAny: any = 10;
let vUnknown: unknown = 10;
let s1: string = vAny;
let s2: string = vUnknown;
unknown
타입의 변수에는 어떤 연산도 직접 수행할 수 없기 때문에 예상치 못한 오류를 방지하기도 합니다.
let vUnknown: unknown = 10;
vUnknown + 20;
vUnknown * 2;
let vUnknown: unknown = 10;
vUnknown + 20;
vUnknown * 2;
결론적으로 unknown
타입은 정말 어떤 타입의 데이터가 넘어올지 예측할 수 없는 상황일 경우 사용해야 하며, any
타입은 컴파일에러를 일단 통과해야하는 급박한 상황이 아니라면 사용하지 말아야 합니다.
1.8 null
let emptyValue: null = null;
let emptyValue: null = null;
값이 없음을 나타내는 null
에 해당되는 타입입니다. undefined
와는 다르게 명시적으로 아무런 값이 없는 상태를 나타내기 위해 사용됩니다.
💡 보통 예시와 같이 null
이나 undefined
로 타입을 고정하여 사용하진 않습니다.
1.9 object
객체 형태로된 모든 타입을 할당 가능합니다. 이러한 이유로 특정한 대상을 가르키지는 못하기 때문에 타입의 안정성을 보장하지 못합니다. 때문에 사용이 권장되지 않는 타입입니다.
function logFunc(obj: object) {
console.log(obj);
}
logFunc({ name: "licat", age: 20 }); // 객체 전달
logFunc([1, 2, 3]); // 배열 전달
logFunc(() => console.log("Hello")); // 함수 전달
function logFunc(obj: object) {
console.log(obj);
}
logFunc({ name: "licat", age: 20 }); // 객체 전달
logFunc([1, 2, 3]); // 배열 전달
logFunc(() => console.log("Hello")); // 함수 전달
이번에는 object를 생성할 때를 보도록 하겠습니다.
const obj: object = {
name: "licat",
age: 3
}
console.log(obj.name); // 경고
console.log(obj["name"]);
console.log(obj["age"]);
const obj: object = {
name: "licat",
age: 3
}
console.log(obj.name); // 경고
console.log(obj["name"]);
console.log(obj["age"]);
위와 같이 선언했을 때 obj.name
을 찍었을 때 경고를 보여줍니다. 이는 object 타입에는 name이라는 속성이 존재하지 않기 때문입니다. 대괄호를 사용하여 속성에 접근하는 것은 가능합니다.
object 사용보다는 아래와 같은 형태의 선언을 권장합니다.
// 방법 1: 인터페이스 사용
interface Person {
name: string;
age: number;
}
const person: Person = {
name: "licat",
age: 20
};
// 방법 2: 타입 별칭 사용
type User = {
name: string;
age: number;
};
const user: User = {
name: "licat",
age: 20
};
// 방법 3: 인라인 타입 정의
const employee: {
name: string;
age: number;
} = {
name: "licat",
age: 20
};
// 방법 1: 인터페이스 사용
interface Person {
name: string;
age: number;
}
const person: Person = {
name: "licat",
age: 20
};
// 방법 2: 타입 별칭 사용
type User = {
name: string;
age: number;
};
const user: User = {
name: "licat",
age: 20
};
// 방법 3: 인라인 타입 정의
const employee: {
name: string;
age: number;
} = {
name: "licat",
age: 20
};
1.10 array
타입스크립트에서는 배열을 어떤식으로 선언하는지 살펴보겠습니다.
const numArr = [1, 2, 3];
const numArr = [1, 2, 3];
배열을 하나 만들고 변수에 저장합니다. 그리고 타입스크립트가 숫자로만 만들어진 배열의 타입을 어떻게 추론하고 있는지 확인 해보겠습니다.
object
나 array
형식이 아닌 number
형식으로 추론하고 있습니다. 그렇다면 number
가 아닌 값을 넣어보고 어떻게 추론하는지 살펴보도록 하겠습니다.
const numArr = [1, 2, 3];
numArr.push(4);
numArr.push("a"); // 경고
console.log(numArr);
const numArr = [1, 2, 3];
numArr.push(4);
numArr.push("a"); // 경고
console.log(numArr);
위와 같이 실행했을 때에는 경고를 주고 아래와 같이 실행하면 경고 없이 타입을 추론합니다.
const numArr = [1, 2, 3, 'a'];
console.log(numArr);
const numArr = [1, 2, 3, 'a'];
console.log(numArr);
위 numArr는 숫자와 문자열이 섞여있는 배열이기 때문에 number[] | string[]
로 추론합니다. 이런형태를 Union Type
이라고 부릅니다.
여러 타입들의 추론이 잘 되는지 확인해보도록 하겠습니다.
const num: number = 10;
const numArr = [1, 2, 3];
const strArr = ['a', 'b', 'c'];
const boolArr = [true, false, true];
const objArr = [{ name: 'licat', age: 20 }, { name: 'cat', age: 30 }];
const arrArr = [[1, 2], [3, 4], [5, 6]];
const mixArr = [1, 2, 3, 'a', 'b', 'c']
console.log(num);
console.log(numArr);
console.log(strArr);
console.log(boolArr);
console.log(objArr);
console.log(arrArr);
console.log(mixArr);
const num: number = 10;
const numArr = [1, 2, 3];
const strArr = ['a', 'b', 'c'];
const boolArr = [true, false, true];
const objArr = [{ name: 'licat', age: 20 }, { name: 'cat', age: 30 }];
const arrArr = [[1, 2], [3, 4], [5, 6]];
const mixArr = [1, 2, 3, 'a', 'b', 'c']
console.log(num);
console.log(numArr);
console.log(strArr);
console.log(boolArr);
console.log(objArr);
console.log(arrArr);
console.log(mixArr);
타입스크립트에서는 아래와 같이 명시적으로 배열 타입을 만들 수 있습니다.
const arr: number[] = [1, 2, 3];
console.log(arr[0]);
const arr: number[] = [1, 2, 3];
console.log(arr[0]);
1.11 tuple
튜플은 고정된 수의 요소를 가지며, 각 요소가 고유한 타입을 가질 수 있는 배열 유형입니다. 튜플은 특정 위치에 특정 타입이 오도록 엄격하게 타입을 지정할 수 있어, 사용자가 미리 정의된 각 위치에 해당하는 타입에 맞는 값을 할당해야 합니다.
let x: [string, number];
x = ['hello', 10]; // OK
let x: [string, number];
x = ['hello', 10]; // OK
튜플은 선언할 때 지정된 요소의 수를 가집니다. 배열과는 다르게 요소를 추가하거나 제거하여 길이를 변경하는 것은 허용되지 않습니다. 때문에 원소의 개수가 정해져 있을 때 사용합니다.
배열은 같은 타입의 원소들을 가지며, 원소의 수는 고정되지 않았습니다. 예를 들어, number[]
또는 Array<number>
는 숫자로 이루어진 배열을 의미합니다.
let list: number[] = [1, 2, 3];
let list: number[] = [1, 2, 3];
반면에, 튜플은 각 원소의 타입과 순서가 고정된 배열입니다. 이를 통해 튜플은 서로 다른 타입의 원소들로 구성될 수 있습니다.
let x: [string, number];
x = ['hello', 10]; // OK
let x: [string, number];
x = ['hello', 10]; // OK
결과적으로 타입스크립트에서의 배열 타입은 원소의 타입이 모두 동일하고 원소의 개수를 알 수 없을 때 사용하며, 튜플은 원소의 타입이 다르거나 원소의 개수가 정해져 있을 때 사용합니다.
언제 튜플을 사용하면 좋을까요?
의미 있는 이름 사용: 튜플 내의 각 요소에 디스트럭쳐링을 이용한 의미 있는 이름을 할당하여 가독성을 높이고 다른 사람들이 각 값의 목적을 이해할 수 있도록 도와줄 수 있습니다. 예를 들어, 좌표를 나타내기 위해 [x, y] 대신 [latitude, longitude]와 같은 이름을 생각해볼 수 있습니다.
불변성: 튜플은 기본적으로 불변입니다. 튜플의 값을 직접 수정하려고 하면 컴파일 오류가 발생합니다. 이는 원래의 데이터를 보존하도록 해 데이터의 추적을 용이하게 합니다.
1.12 void
void
타입은 함수가 반환하는 값이 없음을 나타냅니다.
function warnUser(): void {
console.log('This is my warning message');
}
function warnUser(): void {
console.log('This is my warning message');
}
실제로 void라는 값을 반환하지 않고 함수를 실행시켜보면 undefined가 반환됩니다.
함수뿐만 아니라 일반적인 변수에 사용하는것도 가능합니다. 하지만 이때는 undefined
, null
만 할당이 가능합니다. 때문에 변수와는 사용할 일이 없습니다.
let test1: void = null;
let test2: void = undefined;
let test3: void = 100;
let test4: void = "hello";
let test1: void = null;
let test2: void = undefined;
let test3: void = 100;
let test4: void = "hello";
1.13 never
never
타입은 void 처럼 함수의 반환 타입으로 사용되며 절대 아무런 값을 반환하지 않을 경우 사용합니다. 예를 들어, never
는 함수가 항상 오류를 발생시키거나, 항상 끝나지 않는 경우에 사용됩니다.
// 실행하면 반드시 오류를 던지는 함수의 경우
function error(message: string): never {
throw new Error(message);
}
try {
error('never test');
} catch (e) {
console.error(e);
}
// 실행하면 반드시 오류를 던지는 함수의 경우
function error(message: string): never {
throw new Error(message);
}
try {
error('never test');
} catch (e) {
console.error(e);
}
function infiniteLoop(): never {
while (true) {
}
}
function infiniteLoop(): never {
while (true) {
}
}
2. 연습문제
2.1 기본 타입 지정하기
다음 변수들의 타입을 올바르게 지정해보세요.
// 여기에 알맞은 타입을 지정하세요
let userName = "김개발";
let userAge = 25;
let isStudent = true;
let numbers = [1, 2, 3, 4, 5];
let tuple = ["typescript", 100];
// 여기에 알맞은 타입을 지정하세요
let userName = "김개발";
let userAge = 25;
let isStudent = true;
let numbers = [1, 2, 3, 4, 5];
let tuple = ["typescript", 100];
2.2 타입 추론 이해하기
다음 코드에서 발생할 수 있는 타입 관련 오류를 찾고 수정해보세요.
let value = "Hello";
value = 42;
let numbers = [1, 2, 3];
numbers.push("4");
let mixed = [1, "two", 3];
mixed.push(true);
let value = "Hello";
value = 42;
let numbers = [1, 2, 3];
numbers.push("4");
let mixed = [1, "two", 3];
mixed.push(true);
2.3 void와 never 이해하기
다음 함수들의 반환 타입을 올바르게 지정해보세요.
// 적절한 반환 타입을 지정하세요
function logMessage(message) {
console.log(message);
}
function throwError(message) {
throw new Error(message);
}
function infiniteLoop() {
while (true) {
console.log("무한 루프");
}
}
// 적절한 반환 타입을 지정하세요
function logMessage(message) {
console.log(message);
}
function throwError(message) {
throw new Error(message);
}
function infiniteLoop() {
while (true) {
console.log("무한 루프");
}
}
2.4 변수 순회하기
다음 변수를 순회하면서 하나씩 출력하는 코드를 작성하세요.
["apple", "banana", "cherry"];
["apple", "banana", "cherry"];
3. 연습문제 정답
3.1 기본 타입 지정하기
let userName: string = "김개발";
let userAge: number = 25;
let isStudent: boolean = true;
let numbers: number[] = [1, 2, 3, 4, 5];
let tuple: [string, number] = ["typescript", 100];
let userName: string = "김개발";
let userAge: number = 25;
let isStudent: boolean = true;
let numbers: number[] = [1, 2, 3, 4, 5];
let tuple: [string, number] = ["typescript", 100];
3.2 타입 추론 이해하기
let value: string = "Hello";
// value = 42; // 오류: string 타입에 number를 할당할 수 없음
value = "42"; // 정상: string 타입에 string을 할당할 수 있음
let numbers: number[] = [1, 2, 3];
// numbers.push("4"); // 오류: number[] 배열에 string을 추가할 수 없음
numbers.push(4); // 정상: number[] 배열에 number를 추가할 수 있음
let mixed: (number | string)[] = [1, "two", 3];
// mixed.push(true); // 오류: (number | string)[] 배열에 boolean을 추가할 수 없음
mixed.push("four"); // 정상: (number | string)[] 배열에 string을 추가할 수 있음
// 또는 mixed와 같은 경우 아래와 같이 boolean을 추가할 수 있습니다.
// let mixed: (number | string | boolean)[] = [1, "two", 3];
// mixed.push(true);
let value: string = "Hello";
// value = 42; // 오류: string 타입에 number를 할당할 수 없음
value = "42"; // 정상: string 타입에 string을 할당할 수 있음
let numbers: number[] = [1, 2, 3];
// numbers.push("4"); // 오류: number[] 배열에 string을 추가할 수 없음
numbers.push(4); // 정상: number[] 배열에 number를 추가할 수 있음
let mixed: (number | string)[] = [1, "two", 3];
// mixed.push(true); // 오류: (number | string)[] 배열에 boolean을 추가할 수 없음
mixed.push("four"); // 정상: (number | string)[] 배열에 string을 추가할 수 있음
// 또는 mixed와 같은 경우 아래와 같이 boolean을 추가할 수 있습니다.
// let mixed: (number | string | boolean)[] = [1, "two", 3];
// mixed.push(true);
3.3 void와 never 이해하기
function logMessage(message: string): void {
console.log(message);
}
function throwError(message: string): never {
throw new Error(message);
}
function infiniteLoop(): never {
while (true) {
console.log("무한 루프");
}
}
function logMessage(message: string): void {
console.log(message);
}
function throwError(message: string): never {
throw new Error(message);
}
function infiniteLoop(): never {
while (true) {
console.log("무한 루프");
}
}
3.4 변수 순회하기
const fruits: string[] = ["apple", "banana", "cherry"];
for (let fruit of fruits) {
console.log(fruit);
}
// index로 순회
// 일반적으로 많이 겪는 타입스크립트에 대한 문제입니다. 생략할 것이냐, 명시할 것이냐의 문제입니다.
// 저 for에서 문제가 생길일은 없습니다. 그리고 추론도 잘 해줍니다. 이러한 경우에는 생략하는 것이 일반적입니다.
// 다만 이렇게 순회하려는 접근이 모던하지 않습니다. google coding convention에도 언급되어 있습니다. 객체의 요소를 순회할 때는 for of를 사용합니다. for of 문에서는 타입을 명시하지 않습니다.
for (let i: number = 0; i < fruits.length; i++) {
console.log(fruits[i]);
}
const fruits: string[] = ["apple", "banana", "cherry"];
for (let fruit of fruits) {
console.log(fruit);
}
// index로 순회
// 일반적으로 많이 겪는 타입스크립트에 대한 문제입니다. 생략할 것이냐, 명시할 것이냐의 문제입니다.
// 저 for에서 문제가 생길일은 없습니다. 그리고 추론도 잘 해줍니다. 이러한 경우에는 생략하는 것이 일반적입니다.
// 다만 이렇게 순회하려는 접근이 모던하지 않습니다. google coding convention에도 언급되어 있습니다. 객체의 요소를 순회할 때는 for of를 사용합니다. for of 문에서는 타입을 명시하지 않습니다.
for (let i: number = 0; i < fruits.length; i++) {
console.log(fruits[i]);
}