[Typescript] Type
Documentation - Everyday Types
The language primitives.
www.typescriptlang.org
타입스크립트 타입에 대해 알아보겠습니다.
Type
타입스크립트는 자바스크립트의 기본 타입을 확장하여 더 많은 타입을 제공합니다.
기본 타입 string, number, boolean, undefined, null, symbol, object 이외에 다음과 같은 타입을 제공합니다.
any
any는 모든 타입을 할당할 수 있는 타입입니다.
타입스크립트에서 타입 검사를 하지 않길 원할 때 사용합니다.
따라서 기본 자바스크립트처럼 동작합니다.
tsc 컴파일 시 noImplicitAny 를 사용하면 any로 간주할 때 에러를 발생시킵니다.
let a : any = 10;
// 자바스크립트처럼 동작
a = 'string';
a.push(1);
unknown
unknown 은 모든 타입을 할당할 수 있다는 점에서 any와 비슷하지만 약간의 차이가 있습니다.
any 타입은 모든 타입에 호환될 수 있으나 unknown 의 경우 자기 자신과 any에만 호환될 수 있습니다.
let a : any = 10;
let b = 20;
// any 타입은 number에 할당 가능
b = a;
---------------------------------
let a : unknown = 10;
let b = 20;
// unknown 타입은 number에 할당 불가
b = a; -> Error
never
never 타입은 반환되지 않는 값 또는 절대 도달할 수 없는 값을 의미합니다.
function fail() : never {
// 에러 발생 시 never
throw new Error();
}
---------------------------------
functoin func(x : string | number){
if (typeof x === "string") {
//...
} else if (typeof x === "number") {
//...
} else {
// 절대 도달할 수 없는 값
x;
}
}
리터럴 타입
리터럴 타입은 구체적 문자열 또는 숫자로 이루어진 타입입니다.
let a : "hello" = "hello";
// "hello" 외의 값을 허용하지 않음
a = "hi";
리터럴 타입은 유니온 타입과 함께 사용할 경우 가능한 모든 타입의 조합을 제공합니다.
type EmailLocaleIDs = "welcome_email" | "email_heading";
type FooterLocaleIDs = "footer_title" | "footer_sendoff";
type AllLocaleIDs = `${EmailLocaleIDs | FooterLocaleIDs}_id`;
// "welcome_email_id" | "email_heading_id" | "footer_title_id" | "footer_sendoff_id"
type Lang = "en" | "ja" | "pt";
type LocaleMessageIDs = `${Lang}_${AllLocaleIDs}`;
// "en_welcome_email_id" | "en_email_heading_id" | "en_footer_title_id" | "en_footer_sendoff_id"
// "ja_welcome_email_id" | "ja_email_heading_id" | "ja_footer_title_id" | "ja_footer_sendoff_id"
// "pt_welcome_email_id" | "pt_email_heading_id" | "pt_footer_title_id" | "pt_footer_sendoff_id"
유니온 타입
유니온 타입은 여러 타입을 조합하여 만들 수 있는 새로운 타입입니다.
연산자 `|`, `&`를 사용해서 만들 수 있습니다.
// 문자열, 숫자를 받는 변수
let a : string | number =10;
a = "asdafd";
// 특정 문자열을 허용하는 변수
let signal : "red" | "blue" | "yellow" = "red";
유니온 타입을 사용하여 새로운 타입을 생성할 수 있습니다.
// 타입의 확장
type name = {
name : string;
}
type age = {
age : number;
}
// name, age 를 프로퍼티로 받는 타입
type human = name & age;
let jason : human = {
name : "jason",
age : 20
}
유니온 타입 등 여러 가지 타입을 가질 수 있는 변수를 사용할 때는 주의할 점이 존재합니다.
바로 해당 변수가 가질 수 있는 모든 타입에 유효한 메서드만 사용 가능하다는 점입니다.
function func(id : string | number){
// Property 'toUpperCase' does not exist on type 'string | number'.
// Property 'toUpperCase' does not exist on type 'number'.
console.log(id.toUpperCase()); -> Error
}
타입스크립트에서는 Narrowing 이라는 기법을 사용하여 어떤 값의 타입을 구체적으로 추론할 수 있습니다.
function func(id : string | number) {
if(typeof id === "string"){
// 타입스크립트는 이곳에서 id가 string임을 추론합니다.
console.log(id.toUpperCase());
} else {
// 이곳의 id 타입은 number로 추론합니다.
}
}
타입 별칭과 인터페이스
타입스크립트에서 타입을 재사용하고 싶을 경우, 타입 별칭 또는 인터페이스를 사용할 수 있습니다.
type
// 객체의 프로퍼티 설정
type Point = {
x : number;
y : number;
// 프로퍼티에 ?를 사용하여 옵셔널 프로퍼티 생성 가능
z? : number;
};
// x,y 값을 가지는 pt 를 매개변수로 받음
function printCoord(pt : Point){
console.log(pt.x, pt.y);
}
-------------------------------------
// 유니온 타입의 별칭 설정 가능
type ID = string | number;
interface
interface Point {
x : number;
y : number;
// 프로퍼티에 ?를 사용하여 옵셔널 프로퍼티 생성 가능
z? : number;
}
// x,y 값을 가지는 pt 를 매개변수로 받음
function printCoord(pt : Point){
console.log(pt.x, pt.y);
}
type / interface 의 확장
type 의 경우 & 키워드를 통해 확장할 수 있습니다.
동일한 이름의 타입별칭을 허용하지 않습니다.
type Atype = {
//...
}
type Btype = {
//...
}
// 동일한 타입 별칭 허용 X
type Atype = {} -> Error
// 타입 별칭의 확장
type Ctype = Atype & Btype
interface 의 경우 extends 키워드를 통해 확장할 수 있습니다.
동일한 이름의 인터페이스는 자동으로 합쳐집니다.
interface Atype {
name : string;
}
// 중복된 이름의 인터페이스는 하나로 합쳐집니다.
interface Atype {
age : number
}
// 결과는 다음과 같습니다.
// interface Atype {
// name : string;
// age : number;
// }
// 단, 각 프로퍼티는 호환되는 타입이어야 합니다.
interface Atype {
name : number; -> Error
}
interface Btype {
name : number;
}
// 호환되지 않는 프로퍼티 간 확장 시 해당 타입은 never 타입입니다.
type Ctype = AType & BType
// 다음과 같습니다.
// type Ctype = {
// name : never;
// }
----------------------------------------------------
// extends 키워드를 통해 확장 가능합니다.
interface Atype {
name : string;
}
interface Btype extends Atype {
// name : string 이 존재합니다.
age : number;
}
type vs interface
인터페이스와 타입 별칭은 기능적으로 동일하나 몇 가지 차이점이 존재합니다.
- 확장 방식
// type
type Animal = {
name: string
}
type Bear = Animal & {
honey: Boolean
}
----------------------------------
// interface
interface Animal {
name: string
}
interface Bear extends Animal {
honey: boolean
}
- 타입의 경우 새 프로퍼티 추가가 불가능, 인터페이스는 자유롭게 가능
// type
type Window = {
title: string
}
type Window = {
ts: TypeScriptAPI
} -> Error: Duplicate identifier 'Window'.
----------------------------------
// interface
interface Window {
title: string
}
// Window 에 ts 프로퍼티 추가
interface Window {
ts: TypeScriptAPI
}
Array
자바스크립트에서 배열은 항상 어떤 타입의 값이든 포함 가능합니다.
타입스크립트에서의 배열은 선언 시 특정 타입의 요소만을 지정할 수 있습니다.
// javascript
let list = [1,2,3];
// 어떤 타입이든 추가할 수 있습니다.
list.push(true);
list.push('12');
------------------------------------
// typescript
let list = [1,2,3]; // 생성 시 Array 또는 number[]로 타입 추론
list.push(true); -> Error
또한 타입스크립트는 읽기 전용 배열 ReadonlyArray 를 제공합니다.
let a : ReadonlyArray = [ 'asda', 'dsts', 'zz' ];
// 조작 불가
a.push('dadsa); -> Error
Array 에 ReadonlyArray 타입은 할당할 수 없습니다.
let x: readonly string[] = [];
let y: string[] = [];
// ReadonlyArray에 Array 할당 가능
x = y;
// 반대는 불가능
y = x; -> Error
Tuple
튜플은 요소의 개수와 타입이 정확하게 지정된 배열을 의미합니다.
배열 [ ] 내부에 타입을 선언하여 사용할 수 있습니다.
function func(x : [string, number]) {
let a = x[0]; // string
let b = x[1]; // number
}
튜플은 나머지 요소를 가질 수 있으며 배열/튜플 타입이 올 수 있습니다.
function func(x : [string, number, ...boolean[]){};
readonly 를 사용하여 읽기전용 튜플을 만들 수 있습니다.
function doSomething(pair: readonly [string, number]) {
// ...
}
함수
타입스크립트에서는 함수의 매개변수 타입, 반환 값 타입을 지정할 수 있습니다.
function func(x : string) : string {
return x;
}
// 아무것도 반환하지 않으면 void 타입 반환
function func2() : void {}
익명 함수, 화살표 함수가 선언된 곳에서 해당 함수의 매개 변수의 타입을 추론할 수 있습니다.
const names = ["Alice", "Bob", "Eve"];
// 타입스크립트는 s를 string으로 추론
names.forEach((s) => {
console.log(s.toUpperCase());
});
객체
자바스크립트에서 객체는 프로퍼티를 가지는 값을 의미합니다.
타입스크립트에서 해당 프로퍼티의 타입, 권한 등 여러 가지 설정을 할 수 있습니다.
- readonly : 객체의 프로퍼티 값을 읽기 전용으로 설정
- ? : 프로퍼티 뒤에 붙을 경우 해당 값이 필수적이지 않음을 알림
type human = {
name : string,
age : number,
nickname? : string, // 옵셔널 프로퍼티
}
const jason = {
readonly name : "jason"
age : 20,
// nickname 은 필수 프로퍼티가 아니기 때문에 생략 가능
}
// 필수 프로퍼티는 삭제 불가
// delete jason.age; -> ERROR!
// const 는 변수의 프로퍼티 값 변경을 막지 않음
jason.age = 21
// readonly 프로퍼티의 경우에만 프로퍼티 값 변경을 제한
jason.name = "jack" -> Error
객체 고정하기
객체 프로퍼티 전체를 고정할 경우 as const 를 사용합니다.
as const 로 상수가 된 객체는 하나의 리터럴 타입이 될 수 있습니다
const human = {
name : 'jason',
age : 20
} as const
Enum
Enum은 이름이 있는 상수의 집합입니다.
각 프로퍼티는 값을 가지고 있으며 기본적으로 첫 프로퍼티의 값을 0으로 시작하여 1씩 증가합니다.
enum Direction {
// 프로퍼티의 값을 할당할 수 있습니다.
Up = 1,
// 이후의 값은 1씩 증가합니다.
Down,
Left,
Right,
}
Enum은 타입스크립트의 객체에 as const 를 한 것과 동일한 기능을 제공합니다.
'Javascript > Typescript' 카테고리의 다른 글
[Typescript] Typescript (1) | 2025.03.13 |
---|