zero-wiki Help

타입

타입

타입이란

컴퓨터의 메모리 공간은 한정적입니다. 따라서 특정 메모리의 값을 효율적으로 저장하기 위해서는 메모리 공간을 차지할 값의 크기를 알아야 한다. 값의 크기를 명시한다면 컴퓨터가 값을 참조할 때 메모리 낭비가 심하지 않을 것이다.

또한 변수에 저장할 수 있는 값의 종류는 프로그래밍 언어마다 다릅니다. 최신 자바스크립트의 타입은 7가지 데이터 자료형을 의미합니다.

  • undefined

  • null

  • Boolean

  • String

  • Symbol

  • Numeric

  • Object

이와 같은 유형을 데이터타입 또는 자료형이라고 합니다.

데이터 타입은 여러 종류의 데이터를 분류하여 컴파일러에 값의 형태를 알려줍니다.

이후 저장된 값을 통해 모든 데이터를 해석할 수 있으며 개발자는 타입을 사용하여 값의 종류를 명시할 수 있고 메모리를 보다 효율적으로 관리할 수 있다.

집합으로서의 타입

프로그래밍에서의 타입은 수학의 집합과 유사합니다. 타입은 값이 가질 수 있는 유효한 범위의 집합을 말합니다.

const num: number = 123; const str: string = "abc"; function finc(n: number) { // ... } func(num); func(str); // Argument of type 'string' is not assignable to parameter of type 'number'

어떤 값이 T 타입이라면 컴파일러는 이 값으로 어떤 일을 할 수 있고, 어떤 일을 할 수 없는지를 사전에 알 수 있습니다.

function double(n: number) { return n * 2; } double(2); // 4 double("z"); // // Error: Argument of type 'string' is not assignable to parameter of type 'number'

double() 의 내부 동작을 살펴보면 숫자를 인자로 받을 거라고 기대하는 것을 알 수 있습니다. 만약 인자로 숫자가 아닌 다른 타입의 값을 집어넣을 경우에는 원하는 값을 얻지 못합니다.

함수의 매개변수 타입을 명시한다면 타입스크립트는 곧바로 컴파일 에러를 발생시킵니다.

function double(n: number) { return n * 2; } double(2); // 4 double("z"); // Error: Argument of type 'string' is not assignable to parameter of type 'number' (2345)

정적 타입과 동적 타입

자바스크립트는 컴파일 이전에 타입을 직접 정의해줄 필요가 없었습니다. 컴파일 단계에서 타입을 정의했는지에 따라 정적 타입과 동적 타입으로 구분 할 수 있습니다.

정적 타입 시스템에서는 모든 변수의 타입이 컴파일타임에 결정됩니다. 번거롭지만 컴파일 단계에서 타입 에러를 찾을 수 있습니다. ex) 자바, C, 타입스크립트

동적 타입 시스템에서는 변수 타입이 런타임시에 결정이 됩니다, 때문에 파이썬, 자바스크립트가 대표적인 동적 타입 언어로 개발자는 직접 타입을 정의해줄 필요가 없습니다. ex) 자바스크립트, 파이썬

동적 타임 시스템에서는 마음대로 코드를 작성할 수 있지만 언제 타입 오류가 생길지 모르는 불안감에 휩싸이게 됩니다.

런타임에 타입을 예측할 수 없다면 위험한 상황입니다. 만약 number 타입으로 인자로 들어올 값을 생각하고 있었지만 string 타입의 값을 가져온다면 예상치 못한 결과를 반환해서 오류가 발생하기도 합니다.

function multiplyByThree(number) { return number * 3; }; multiplyByThree(10); // 30 multiplyByThree("f"); // NaN

강타입과 약타입

타입이 결정되는 시점은 다르지만 모든 프로그래밍 언어에는 타입이 존재합니다. 자바스크립트도 명시를 해주지 않아도 되지만 나름대로 이해하려고 노력하고 있습니다.

개발자가 의도적으로 타입을 명시하지 않았지만 자동으로 변경되는 것을 암묵적 타입 변환이라고 합니다.

암묵적 타입 변환 여부에 따라 시스템을 강타입, 약타입으로 분류할 수 있습니다.

강타입 특징을 가진 언어에서는 다른 타입을 갖는 값끼리 연산을 시도하면 컴파일러 또는 인터프리터 단계에서 에러가 발생합니다.

이에 반해 약타입의 특징을 가진 언어에서는 특정한 값의 타입을 변환하여 연산을 수행한 후 값을 도출합니다.

C++

#include <iostream> int main(){ std:cout << "2" - 1 ; // '2'는 아스키 값으로 50입니다. }

자바

class Main { public static void main(String[] args){ System.out.println('2' - 1); } }
sh -c javac -classpath .:target/dependency/* -d . $(find . -type f -name '*.java') > java -classpath .:target/dependency/* > Main49

파이썬

print('2' - 1) Traceback (most recent call last): File "main.py" , line 1, in <module> print('2' - 1) TypeError: unsupported opperand type(s) for -: 'str' and int

루비

puts "2" - 1
> bundle exec ruby main.rb Traceback (most recent call last): main .rb:1:in `<main>': undefined method `=' for "2": String (NomethodError) Did you mean? -@ exit status 1

자바스크립트

console.log("2" - 1) // 1

타입스크립트

console.log("2" - 1) // '2' error // type error // The left-hand side of an arithetic operation must be of type 'any', 'number', 'bigint' or an enum type

C++, 자바, 자바스크립트에서는 서로 다른 타입을 갖는 값끼리의 연산이 자동으로 동작한다.이에 반해 파이썬, 루비, 타입스크립트는 강타입 언어로 분류할 수 있다.

자바스크립트는 약타임 언어이다. 때문에 런타임 시에 발생할 수 있는 에러를 방지하는 것은 프로그램을 안전하게 만드는 데 도움이 된다. 여기서 '안전한'이란 타입 안정성을 뜻한다.

타입 검사기가 프로그램을 타입으로 할당하는 데 사용하는 규칙 집합을 타입 시스템이라고 한다. 타입 시스템은 두 가지로 구분한다. 어떤 타입을 사용하는지를 컴파일러에 명시를 해줘야하는지, 자동으로 타입을 추론을 하는지, 타입스크립트는 두 가지의 영향을 모두 받았다.

컴파일 방식

즉 개발자가 고수준 언어로 작성하면 컴파일러는 컴퓨터가 알 수있는 바이너리 (0과 1로 이루어진)코드로 변환한다.

그러나 타입스크립트의 컴파일은 다르다. 타입스크립트의 컴파일 결과물은 여전히 사람이 이해할 수 있는 방식인 자바스크립트입니다.

이처럼 타입스크립트는 다른 타입으 개념의 언어와 구별되는 특징을 가지고있다 이에 자바스크립트에 타입이라는 레이어를 끼얹은 일종의 템플릿 언어, 확장 언어로 해석하는 의견이 있다.

타입 시스템

타입 애너테이션 방식

변수나 상수 혹은 함수의 인자의 반환 값에 타입을 명시적으로 선언하여 어떤 타입 값이 저장될 것인지를 컴파일러에 직접 알려주는 문법이다.

자바와 C#에서는 변수앞에 타입을 작성한다.

int woowahanNum = 2010; // Integer (whole number) float woowahanFloatNum = 2.01f // Floating point number char woowahanLetter = 'B'; // Charecter boolean woowahanBool = true; // Boolean String woowahanText = "WoowaBros"; // String

이와 달리 타입스크립트에서는 변수 이름 뒤에 : type 구문을 붙여 데이터 타입을 명시해준다.

let isDone: boolean = false; let decimal: number = 6; let color: string = "blue"; let list: number[] = [1, 2, 3]; let x: [string, number]; // tuple

타입스크립트는 기존 자바스크립트 코드에 점진적으로 타입을 적용시킬 수 있는 특징을 가지고 있습니다. 때문에 java와 같이 선언부가 있지 않아도 정상적으로 동작한다. 대신 타입 추론을 하는 과정에서 어려움을 겪을 것이다.

구조적 타이핑

타입을 사용하는데 언어에서 값이나 객체는 하나의 구체적인 타입을 가지고 있다. 타입의 이름은 컴파일 이후에도 남아있으며 이것을 구체화한 것을 타입 시스템이라고 부른다.

class Animal { String name; int age; }

또한 서로 다른 클래스끼리 명확한 상속 관계나 공통으로 가지고 있는 인터페이스가 없다면 타입은 서로 호환되지 않습니다.

interface Developer { faceValue: number; } interface BankNote { faceValue: number; } let developer: Developer = { faceValue: 52 }; let bankNote: BankNote = { faceValue: 10000 }; developer = bankNote; // ok bankNote = developer; // ok

그러나 타입스크립트에서의 타입은 조금 다릅니다. 명목적인 언어의 특징과 달리 타입스크립트는 구조로 타입을 구분합니다. 이것을 구조적 타이핑이라고 합니다.

구조적 서브 타이핑

타입스크립트의 타입 시스템을 집합으로 이해할 수 있습니다. 타입은 단지 집합이 되는 값이고 특정 값은 많은 집합에 포함될 수 있습니다. 따라서 여러 타입을 동시에 가질 수도 있습니다.

type stringOrNumber = string | number;

이처럼 집합으로 나타낼 수 있는 타입스크립트의 타입 시스템을 지탱하고 있는 것이 바로 구조적 서브타이핑이다.

interface Pet { name: string; } interface Cat { name: string; age: number; } let pet: Pet; let cat: Cat = { name: "Zag", age: 2 }; pet = cat; // OK

Cat은 Pet과 다른 타입으로 선언이 되어있지만 같은 이름의 속성을 가지고 있다. 따라서 할당을 해도 문제가 없다.

구조적 서브 타이핑은 함수의 매개변수로도 사용됩니다.

interface Pet { name : string; } let cat = { name: "Zag", age: 2 } function greet(pet: Pet) { console.log("Hello, " + pet.name); } greet(cat);

greet() 함수는 매개변수에 들어갈 수 있는 값을 Pet 타입으로 제한을 두고있다. 하지만 cat 객체를 넣어도 문제 없이 실행이 된다. 그 이유는 Pet 인터페이스가 가지고 있는 name 속성을 사용하기 때문이다.

interface Pet { name : string; age: number; } let cat = { name: "Zag" } function greet(pet: Pet) { console.log("Hello, " + pet.name); } greet(cat); /* Error Argument of type '{ name: string; }' is not assignable to parameter of type 'Pet'. Property 'age' is missing in type '{ name: string; }' but required in type 'Pet'.ts(2345) */

하지만 다음과 같이 name 속성만 사용하지만 객체의 구조가 일치하지 않는 경우 에러가 발생한다.

자바스크립트를 닮은 타입스크립트

타입스크립트의 타입 시스템은 구조적 서브타이핑을 다루고 있다. 이는 C++, 자바의 명목적 타이핑과 반대되는 성격이다.

class Cat { String name; public void hit() {} } class Arrow { String name; public void hit() {} } public class Main { public static void main(String[] args){ // 🚨 error: incompatible types: Cat cannot be converted to Arrow Arrow cat = new Cat(); // 🚨 error: incompatible types: Arrow cannot be converted to Cat Cat arrow = new Arrow(); } }t this.age = age; this.sleepTime = sleepTime; } }

Cat과 Arrow 클래스는 변수와 메소드가 동일하지만 클래스로 생성한 인스턴스는 호환되지 않는 것을 확인할 수 있습니다. 이는 명목적 타이핑을 채택한 언어에서는 구조가 같더라도 이름이 다르다면 다른 타입으로 취급되는 것을 볼 수 있습니다.

function greet(p: Person) { console.log(`Hello, I'm ${p.name}`); } const developer = new Developer("zig", 20, 7); greet(developer); // Hello, I'm zig

명목적 타이핑은 타입의 동일성을 확인하는 과정에서 구조적 타이핑에 비해 안전합니다. 개발자가 의도한 타입이 아니라면 에러를 내뱉으니까요.

하지만 타입스크립트가 구조적 타이핑을 채택한 이유는 자바스크립트를 모델링한 언어이기 때문에 채택을 하였습니다. 자바스크립트는 덕 타이핑을 기반으로 하고있기 때문입니다.

또한 구조적 타이핑 덕분에 더욱 유연한 타이핑이 가능해진 것도 있습니다. 쉬운 사용성안정성 두 가지 목표 사이의 균형을 중시하는 타입스크립트에서는 객체 간 속성이 동일하다면 서로 호환되는 구조적 타입 시스템을 제공하여 편리성을 높였습니다.

덕 타이핑과 구조적 타이핑의 차이 두 구조의 차이는 실제 코드를 보면 차이가 없어보입니다. 그래도 차이가 있다면 이는 타입을 검사하는 시점에 있습니다. 덕 타이핑은 런타임에 타입을 검사합니다.

덕 타이핑은 주로 동적 타이핑, 구조적 타이핑은 주로 정적 타이핑에 검사하는 것으로 알 수 있습니다.

이는 컴파일 이전 타입을 검사하여 에러를 잡아주는 타입스크립트의 특징을 가지고 구조적 타이핑을 쓰는 것을 알 수 있습니다.

구조적 타이핑의 결과

구조적 타이핑은 항상 예상한 결과만을 내보내는 것은 아닙니다.

interface Cube { width: number; height: number; depth: number; } function addLines(c: Cube){ let total = 0; for (const axis of Object.keys(c)){ // 🚨 Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'Cube'. // 🚨 No index signature with a parameter of type 'string' was found on type 'Cube'. const length = c[axis]; total += length; } return total; }

addLines() 함수의 매개변수인 c는 Cube 타입으로 선언되었고, Cube 인터페이스의 모든 필드는 number 타입을 가지기 때문에 c[axis]는 당연히 number 타입일 것이라고 예측할 수 있습니다. 그러나 c에 들어온 객체는 위 속성들 말고도 어떤 속성이든 가질 수 있으므로 c[axis] 타입이 string일 수도 있어서 에러가 발생합니다.

쉽게 말하자면 타입스크립트가 c[axis]가 어떤 속성을 지닐지 알 수 없으면 c[axis] 타입을 number라고 확정할 수 없어서 에러를 발생시킵니다. 타입스크립트의 구조적 타이핑의 특징으로 Cube 타입 값이 들어갈 곳에 name (ex: string 타입의 값을 가지고 있는 추가 속성) 같은 추가 속성을 가진 객체도 할당할 수 있기 때문에 발생하는 문제입니다.

에러를 없애려면 다음과 같이 type assertion을 통해 진행할 수도 있습니다.

function addLines(c: Cube){ let total = 0; for (const axis of Object.keys(c)){ const length = c[axis as keyof Cube]; total += length } return total }

이러한 한계를 극복하고자 명목적 타이핑 언어의 특징을 식별할 수 있는 유니온 같은 방법이 생겨났습니다.

타입스크립트의 점진적 타입 확인

타입을 지정한 변수와 표현식은 정적으로 타입을 검사하지만 타입 선언이 생력되면 동적으로 검사를 수행합니다. 이 선언을 생략하면 암시적 타입 변환이 일어납니다.

function add(x, y){ return x + y; } // 위 코드는 아래와 같이 암시적 타입 변환이 일어납니다. function add(x: any, y: any): any;

타입스크립트는 x와 y의 타입이 잘못된 것이라고 생각하지 않는다. 대신 타입이 정해져있지 않으니 x와 y 각각 any 타입이라고 타입 추론을 진행한다.

이처럼 타입스크립트는 필요에 따라 타입을 생략할 수도, 타입을 점진적으로 추가할 수도 있다. 타입스크립트에서 프로그램을 컴파일하는 데 반드시 모든 타입을 알아야 하는 것은 아닙니다.

그러나 타입스크립트는 컴파일 타임에 프로그램의 모든 타입을 알고 있을 때 최상의 결과를 보여줍니다.

타입스크립트 .ts 파일에서 자바스크립트 문법으로 소스코드를 작성하더라도 문제는 발생하지 않습니다. 때문에 .js 파일을 .ts 파일로 마이그레이션 할 때 점진적 타이핑이라는 특징을 유용하게 활용 할 수 있습니다.

그러나 이 특징이 꼭 좋은 것은 아닙니다. 타입스크립트는 정적 타입의 정확성을 100% 보장해주지 않기 때문에 모든 변수와 표현식의 타입을 컴파일 타임에 검사하지 않아도 되기에 타입을 지정하지 않을 경우 런타임에 에러가 발생하기도 합니다.

const names = ["zig", "colin"]; console.log(names[2].toUpperCase()); // 🚨TypeError: Cannot read property 'toUpperCase' of undefined

자바스크립트 슈퍼셋으로서의 타입스크립트

타입스크립트는 기존 자바스크립트 코드에 정적인 타이핑을 추가한 것으로 자바스크립트의 상위 집합이다. 문법 또한 자바스크립트의 문법을 모두 포함하고 있기 때문에 타입스크립트를 도입하는 데 진입장벽이 낮습니다.

모든 자바스크립트 코드는 타입스크립트라고 볼 수 있지만, 반대로 모든 타입스크립트 코드가 자바스크립트인 것은 아닙니다. 명시를 하는 문법이 있기 때문에.

값 vs 타입

값은 프로그램이 처리하기 위해 메모리에 저장하는 모든 데이터이다. 다르게 말하면 프로그램에서 조작하고 다룰 수 있는 어떤 표현이며 다양한 형태의 데이터를 포함할 수 있습니다.

프로그래밍 관점에서는 문자열, 숫자, 변수, 매개변수 등이 값에 해당합니다.

11; // 숫자 값 "Hello word"; // 문자열 값 let foo = "bar"; // 변수 값

객체 역시 값이다. 그리고 자바스크립트에서는 함수도 값이다. 모든 것이 객체인 언어답게 런타임에 객체로 변환되기 때문이다.

타입스크립트를 들어가면서 타입이라는 개념이 등장한다. 타입스크립트는 변수, 매개변수, 객체 속성 등에 : type 형태로 타입을 명시한다.

const a : string = "hello"; const b : number = 202; const c : boolean = true; const d : number[] = [1, 2, 3];

또는 type이나 interface 키워드로 커스텀 타입을 정의할 수도 있다.

type Person = { name : string; age : number; } interface Person { name : string; age : number; }

값 공간과 타입 공간의 이름은 서로 충돌하지 않기 때문에 타입과 변수를 같은 이름으로 정의할 수 있는데 타입스크립트가 자바스크립트의 슈퍼셋인 것과 관련이 있습니다. type으로 선언한 내용은 런타임시에 제거되기 때문에 값 공간과 타입 공간은 충돌하지 않습니다.

만약 함수의 매개변수로 사용할 경우 타입과 값을 명확하게 구분해야 한다.

function postTIL(author: Developer, date: Date, content: string): Resopnse{ // ... }

타입스크립트에서는 값과 타입이 함께 사용되지만, 별도의 네임스페이스에 존재합니다.

값과 타입의 구분은 맥락에 따라 달라지기 때문에 값 공간과 타입 공간을 혼동할 때도 있습니다.

function email(options: { person: Person; subject: string; body: string }){ // ... }

자바스크립트에서의 구조 분해 할당을 사용한다면 email 함수의 매개변수로 넘기는 options 객체를 아래와 같이 풀어서 사용할 수 도 있습니다.

function email({ person: Person, // 🚨 subject; string, // 🚨 body : string, // 🚨 }){ // ... }

값의 관점에서 Person과 string이 해석이 되었기에 생긴 에러입니다. 떄문에 다음과 같이 타입을 올바르게 명시를 해야합니다.

function email({ person, subject, body, }: { person: Person, subject: string, body: string }) { // ... }

타입스크립트를 하면서 가장 헷갈리는 부분은 enum과 class 입니다. enum은 런타임에 객체로 변환되는 값을 말합니다. enum은 런타임에 실제 객체로 존재하며 함수로 표현할 수도 있습니다.

enum Direction{ Up, // 0 Down, // 1 Left, // 2 Right // 4 }
enum WeekDays { MON = "Mon", TUES = "Tues", WEDNEDS = "Wednes", THURES = "Thurs", FRI = "Fri" } // type WeekDaysKey = "MON" | "TUES" | "WEDNED" | "THURES" | "FRI" type WeekDaysKey = keyof typeof WeekDays; function printDay(key: WeekDaysKey, message: string){ const day = WeekDays[key] if(day <= WeekDays.WEDNEDS){ console.log(`It's still ${day}day, ${message}`); } } printDay("THURES", "wanna go home")

이 예시에서는 enum이 타입으로 사용되었습니다 WeekDays enum에 keyof typeof 연산자를 사용하여 type WeekDaysKey 를 만들어, printDay()함수의 인자에 넘겨줄 수 있는 값의 타입을 제한하였습니다.

이를 통해 enum은 일반적인 객체처럼 동작하는 것을 확인할 수 있습니다.

자바스클비트의 문법의 여러 키워드가 타입스크립트에서 값 또는 타입으로 해석되는 방식을 정리하면 다음과 같다.

키워드

타입

class

Y

Y

const, let var

Y

N

enum

Y

N

function

Y

N

interface

N

Y

type

N

Y

namespace

Y

N

타입을 확인하는 방법

타입스크립트에서 타입을 확인하는 방법은 typeof, instanceof 그리고 타입 단언을 통해 타입을 확인할 수 있습니다. typeof는 연산하기 전에 데이터 타입을 나타내는 문자열을 반환한다.

typeof

typeof의 중요한 점은 값과 타입에서 사용할 때의 쓰임새가 다르다는 것이다.

값에서 사용할 경우

interface Person { first: string; last: string; } const person: Person = { first: "zig", last: "song" }; function email(options: { person: Person; subject: string; body; string }){}

값에서 사용된 typeof는 자바스크립트 런타임의 typeof 연산자가 된다.

type T1 = typeof person; // 타입은 person type T2 = typeof email; // 타입은 (options: { person: Person; subject: string; body: string; }) => void

값에서 사용할 경우

person 변수가 interface Person 타입으로 선언되었기 때문에 타입 공간에서의 typeof person은 Person을 반환한다. email 함수는 타입공간에서 typeof 연산자로 값을 읽을 때 함수의 매개변수 타입과 리턴 타입을 포함한 함수 시그니처 타입을 반환한다.

const v1 = typeof person; // 값은 object const v2 = typeof email; // 값은 function

예시의 v1과 v2는 const 키워드로 선언된 변수로 값이 할당될 공간이다. 값 공간의 typeof는 피연산자인 person과 email의 런타임을 가리키는 문자열을 반환한다. 즉, 값에서 사용된 typeof 연산자는 자바스크립트 typeof 연산자와 동일하게 사용된다.

자바스크립트의 클래스를 쓸 경우 typeof 연산자를 주의하여 사용하여야 한다.

class Developer { name: string; sleepingTime: number; constructor(name: string, sleepingTime: number){ this.name = name; this.sleepingTime = sleepingTime; } } const d = typeof Developer; // 값이 'function' type T = typeof Developer; // 타입이 typeof Developer

자바스크립트의 클래스는 결국 함수이기 때문에 값 공간에서 typeof Developer의 값은 function이 된다. 타입공간에서의 typeof Developer는 인스턴스 타입이 아니라 new 키워드를 사용할 때 볼 수 있는 생성자 함수를 나타낸다.

const zig: Developer = new Developer("zig", 7); type ZigType = typeof zig; // 타입이 Developer

Developer 클래스로 생성한 zig 인스턴스는 Devloper가 인스턴스 타입으로 생성되었기 때문에 typeof zig 즉, type ZigType은 Developer를 반환한다.

그러나 Developer는 Developer 타입의 인스턴스를 만드는 생성자 함수이다. 따라서 typeof Developer 타입도 그 자체인 typeof Developer가 된다.

즉 typeof Developer를 풀어서 사용하면 다음과 같다.

new (name: string, sleepingTime: number): Developer

instanceof

자바스크립트에서는 instanceof는 프로토타입 체이닝 어딘가에 생성자의 프로토타입 속성이 있는지 판단할 수 있습니다. typeof 연산자처럼 instanceof 연산자의 필터링으로도 안전하게 타입을 정제하여 사용할 수 있습니다.

let error = unknown; if(error instanceof Error){ showAlertModal(error.message); } else { throw Error(error); }

as

타입스크립트에서는 타입 단언이라 부르는 문법을 사용해서 타입을 강제할 수도 있는데 as 키워드를 사용하면 된다.

타입 단언은 해당 값의 타입을 더 잘 파악할 수 있을 때 사용되며 강제 형 변환과 유사한 기능을 제공한다.

const loaded_text: unknown; // 어딘가에서 unknown 타입 값을 전달받았다고 가정 const validateInputText = (text: string) => { if (text.length < 10) return "최소 10글자 이상 입력해야 합니다."; return "정상 입력된 값입니다." }; validateInputText(loaded_text as string); // as 키워드를 사용하여 string으로 강제하지 않을 경우 타입스크립트 컴파일 단계에서 에러가 발생

이외에도 타입을 검사하는데 type-guard 패턴도 있습니다.

원시 타입

타입스크립트는 자바스크립트의 슈퍼셋이기 때문에 대응되는 부분도 있지만 차이점도 있다. 같은 타입을 가지지만 변수는 별도의 타입을 가지지 않는다. 따라서 자바스크립트의 변수에는 어떠한 타입의 값이든 할당할 수 있다.

타입스크립트는 이 변수에 타입을 지정할 수 있는 타입 시스템 체계를 구축한다. 특정 타입을 지정한 변수에 해당 타입의 값만 할당할 수 있는 식이다.

boolean

const isEmpty: boolean = true; const isLoading: boolean = false; // errorAction.type과 ERROR_TEXT가 같은지 비교한 결괏값을 boolean 타입으로 반환하는 함수 function isTextError(errorCode: ErrorCodeType): boolean { const errorAction = getErrorAction(errorCode); if(errorAction) { return errorAction.type === ERROR_TEXT; } return false; }

오직 true와 false만 할당이 가능한 boolean 타입이다. 자바스크립트에는 boolean 원시 값은 아니지만 형 변환을 통해 true / false로 취급되는 Truthy / Falsy 값이 존재한다.

null 값이 비어있을 경우 null 만 할당할 수 있다. 보통 빈 값을 할당해야 할 때 null을 사용한다. 이때 사용된 null은 명시적, 의도적으로 값이 아직 비어있을 수 있음을 보여준다. undefined가 null과 무엇이 다른지 어림짐작할 수 있다.

자바스크립트에서는 null과 undefined를 == 연산자를 이용하여 비교하였을 때 true가 나온다. 하지만 엄연히 다른 존재이다.

type Person1 = { name: string; job?: string; } type Person2 = { name: string; job: string | null; }

모든 사람은 이름과 직업을 가진다고 가정을 해보았을때 현업에 종사 할 수도 혹은 무직일 수도 있다. Person1은 job이라는 속성 유무를 통해 무직의 여부를 알 수 있다. 하지만 Person2는 값이 비어있고 없음을 통해 구별할 수 있다.

type add = (a: number, b: number) => number;

타입스크립트에서 함수 자체의 타입을 명시할 때는 화살표 함수 방식으로만 호출 시그니처를 정의한다.

type vs interfacce

객체를 타이핑하기 위해 주로 사용하는 키워드로 type과 interface가 있다. 중괄호를 사용한 객체 타이핑을 하기 주로 사용한다.

type NoticePopupType = { title: string; description: string; }; interface INoticePopup { title: string; description: string; }; const noticePopup1: NoticePopupType = {...}; const noticePopup2: INoticePopup = {...};

다음과 같이 선언해서 사용할 경우 반복적으로 사용돼도 중복 없이 해당 타입을 사용할 수 있다.

타입스크립트에서는 일반적으로 변수 타입을 명시적으로 선언하지 않아도 자동으로 타입을 추론한다. 이는 컴파일러가 변수 사용 방식과 할당된 값의 타입을 분석하여 타입을 유추한다는 것을 의한다. 따라서 모든 변수에는 명시적으로 선언할 필요가 없다.

그러나 타입 추론에 대해서는 다양한 의견이 있다. 컴파일러에 타입 추론을 온전히 맡길 것인지, 명시적으로 타입을 선언할 것인지는 개인의 취향 또는 팀의 컨벤션에 다라 다를 수 있다.

Last modified: 07 August 2024