이전 포스트에서 타입스크립트를 왜 사용해야하는지에 대해 길게 책 내용을 해석해봤습니다.
결국 정리해보자면 런타임 도중 오류를 발생할 가능성이 있는 타입변환을 정적타입을 도입함으로써 보완해줍니다. 그리고 기존의 자바스크립트에서 구현이 까다로웠던객체지향프로그래밍을 하기 쉽게 적용할 수 있게 해주는 문법들이 추가되었습니다.
(이 부분은 모던 자바스크립트들의 특징이지만 타입스크립트을 통해서도 누릴 수있는 이점입니다.)
타입스크립트를 제대로 시작해보겠습니다. eBook 내용을 기반으로 작성해보겠습니다.
기존 자바스크립트는 함수를 정의할 때, 인자에 어떤 타입의 값이라도 들어갈 수 있습니다.
function doCalculation(
a : number,
b : number,
c : number) {
return (a * b) + c
}
위는 doCaulation함수가 3개의 number 타입의 인자가 필요하다고 정의한 것입니다.
만약 number타입이 아니거나 인자의 개수가 3개가 아니라면 Error가 발생합니다.
책에서는 string, boolean, number 이 타입들에 각각 맞지않는 타입을 넣었을 때 에러가 발생한다는 내용을 길게 적어놓았습니다. 하지만 이 부분은 프로그래머라면 충분히 다 예상할 수 있기 때문에 생략하고 넘어가겠습니다.
타입 스크립트에 사용되는 몇가지 기술을 소개하겠습니다.
타입 스크립트는 변수의 nature을 결정하기위해 inferred typing이라고 불리는 기술을 사용합니다.
var inferredString = "this is a string";
var inferredNumber = 1;
inferredString = inferredNumber;
위와 같이 코드를 작성하고 실행해보면 아마 에러가 발생할 것입니다. 이것이 inferred typing입니다. 타입을 명시하지않아도 맨 처음 할당할 때 해당 변수의 타입이 결정됩니다.
duck pattern 과같이 duck이 많이 나오는데 이 단어의 의미를 저는 여기서 처음알았습니다.
만약 그것이 오리같이 생기고 오리같이 걸으면 아마 그것은 오리일 것입니다.
이 말의 뜻은 만약 두 개의 변수를 비교할 때, 그것들이 같은 properties와 methods를 가지고 있다면, 그것들은 서로 교체(?)될 수 있다는 것을 의미합니다.
var complexType = { name: "myName", id: 1};
complexType = {name: " anothoerName", id: 2};
즉 위와 같이 타입스크립트는 같은 property를 가지는 객체는 같은 타입으로 판단하는 것을 의미합니다. 만일 하나의 프로퍼티라도 타입이 다른거나 없다면 에러를 발생시킬 것입니다.
위에서 소개한 duck typing과 inferred typing은 타입스크립트 언어의 강력한 기능입니다.
이 부분은 ES6에서 도입된 것을 타입스크립트도 사용한다는 내요이니 생략하겠습니다.
console.log(`this is ${testVariable}`);
다음과 같이 포맷팅을 사용할 수 있는 기능입니다. 디버깅할 때 도움이 많이 될 것 같네요.
자바스크립트의 기본타입(string, number, boolean) 이외에도 자바스크립트는 다른 두개의 basic data type을 가지고 있습니다. arrays와 enums입니다.
var arrayOfNumbers: number [] = [1,2,3];
위와 같이 []
을 사용해서 number array타입을 선언할 수 있습니다. 추후에 나오겠지만 pipe line |
을 이용해서 string | number []
string과 number 두개의 타입을 담을 수 있는 배열 타입도 만들 수 있습니다.
배열얘기가 나와서 배열을 사용하는 방법을 몇가지 남기겠습니다. ES6 내용입니다.
위 문법을 사용하면 배열의 요소를 순서대로 loop할 때 용이합니다.
for (var itemKey in arrayOfStrings) {
var itemValue = arrayOfStrings[itemKey];
console.log(`arrayOfStrings[${itemKey}] : ${itemValue}`);
위와 같이 인덱스를 가져올 수 있고
위 문법을 사용하면 배열내의 요소를 바로 가져올 수 있습니다.
for (var itemValue of arrayOfStrings) {
console.log(`arrayItem : ${itemValue}`);
타입스크립트를 사용할 때, any라는 타입을 표시해주면 해당 변수에 어떠한 타입도 넣을 수 있습니다.
Simply Find an Interface for the Any Type(S.F.I.A.Y)
짧게말해 최대한 any type 을 사용하는 것을 피하라고 합니다.
명시적인 타입 캐스팅도 존재합니다.
var item1 = <any> {id: 1, name:"item 1"};
item1 = { id: 2 };
사용법은 위와 같습니다.
OOP 언어들은 항상 Enum타입을 가지고 있습니다. Java, C++, C#
그래서 타입스크립트도 basic type으로 가지고 있습니다.
enum DoorState {
Open,
Close,
Ajar
}
var colorOpenDoor = DoorState.Open;
var colorDoor = DoorState['Close'];
사용법은 객체를 다룰 때와 똑같습니다.
타입 스크립트는 할당되지않은 변수를 사용하는 것을 금지합니다. 하지만 나중에 할당되어야할 경우도 가끔존재합니다. 호이스팅을 이용할 때가 그렇습니다.
let globalString: string;
setGlobalString();
console.log(`globalString: ${globalString}`);
function setGlobalString() {
globalString = "this is the string";
}
만약 실행하면 console.log를 호출할 때는 아마 globalString은 undefined이 아니지만 타입스크립트는 globalString은 할당이 되지않았다고 판단하게됩니다. 해결책은globalString변수에 exclamation mark(!) 를 사용하는 것입니다.
let globalString!: string;
이 표시는 컴파일러에게 이 변수는 값을 할당하기전에 사용해도 에러를 발생하지 말라고 말하는 것과 같습니다. 사용할 때 해당 표시를 해도 동일합니다.
console.log(`globalString: ${globalString!}`);
function addNumbers(a: number, b: number): number{
return a+b
}
함수는 위와같이 타입을 정의합니다. 괄호 뒤의 :number는 리턴값을 의미합니다.
function concateStrings(a: string, b: string, c?:string){
return a+b+c
}
만약 위와 같이 인자에 c?:string
을 정의하면 3번째 인자를 할당하지않아도 에러를 발생하지 않겠죠.(대신 결과에는 undefined 가 붙을 것입니다.)
a, b인자는 반드시 주어져야합니다.
function concateStringDefault(
a: string,
b:string,
c:string="c"){
return a+b+c;
}
위와 같이 default parameter를 설정해서 optional parameter를 나타낼 수 있습니다.
만약 parameter의 개수가 고정적이지 않을 경우, 아래와 같이 할 수 있습니다.
function testArgumets(...argArray: number []){
if(argArray.length > 0){
for (var i = 0; i < argArray.length; i++){
console.log(argArray[i]);
}
}
}
함수형 프로그래밍에서는 함수를 인자로 넘기는 일이 많죠. 그래서 function 의 타입도 지정해줄 수 있습니다.
function doSomethingWithCallback(
initialText: string,
callback: (initialText: string) => void
){
console.log("hello");
callback(initialText);
위와 같이 콜백함수의 인자와 return 타입을 정해줄 수 있습니다. 이 기능은 매우 강력할 것 같습니다.
가끔은 하나의 함수가 여러 타입을 연산하기 원할 때도 있습니다. 자바나 C++에서는 함수 Override를 통해 같은함수가 다른 타입의 연산을 지원해줄 수 있습니다. 타입스크립트도 가능합니다.
function add(a: string, b: string):string;
function add(a: number, b: number):number;
function add(a: any, b: any):any{
return a+b;
}
위와 같이 override를 사용할 수도 있습니다. 대신 정의하지않은 타입인 boolean값을 넣을시 에러가 발생합니다.
조금 고급 타입들을 보겠습니다.
union type은 두개 이상의 다른 타입의 조합으로 type을 표현할 수 있습니다.
var unionType : string | number;
unionType = 1;
unionType = "test";
다음과 같이 pipe symbol(|)를 사용하면 여러 타입을 조합할 수 있습니다.
우리가 생성한 타입에 별칭을 부여함으로써 프로그래밍의 가독성을 올릴 수 있습니다. 앞서 소개한 union type과 함께 사용하면 효과적일 것 같습니다.
type StringOrNumber = string | number;
function addWithAlias(
arg1: StringOrNumber,
arg2: StringOrNumber,
): string {
return arg1.toString() + arg2.toString();
}
위와 같이 string과 number 타입을 동시에 허용하는 타입을 type
을 통해 정의할 수 있습니다. C언어에서 #define을 통해 매크로를 정의하는 것과 비슷하네요.
물론 함수의 타입로 미리 정의할 수 있습니다.
type CallbackWithString =(string) => void;
자바스크립트에서 변수값이 할당되있지않으면 undefine를 돌려줍니다. 하지만 null이라는 값도 가지고 있는데 차이는 아래와 같습니다.
null는 변수가 어디있는지 알지만 값을 가지고 있지않을 때, undefined는 현재 스코프에서 어디에도 정의되있지않을 때 사용됩니다.
타입스크립트의 타입에도 null과 undefined가 있습니다.
아마 null을 허용할 때 union타입으로 사용할 것같습니다.
function testUndef(test: null | number){
console.log("test parameter: " + test);
}
마지막으로 Tuple 타입에 관해 알아보겠습니다.
저는 파이썬을 사용하다가 js로 넘어와서 튜플이 크게 낯설지않습니다. Tuple은 사물의 유한한 순서를 뜻합니다.
let tupleType: [string, boolean];
tupleType = ["test", false];
튜플의 타입정의는 위와같이 square bracket으로 타입을 정의해주면 됩니다.
사용할 때는 아래와같이 사용하거나 배열처럼 사용하면 될 것같습니다.
let [e1, e2] = tupleType;
function useTupleAsRest(...args: [number, string, boolean]){
let [arg1, arg2, arg3] = args;
...
}
다음과 같이 rest 인자들의 타입을 튜플로 정해줄 수 있고
type RestTupleType = [number, ...string[]];
let restTuple: RestTupleType = [1, "string1", "string2", "string3"]
type alias를 통해 rest인자를 받을 수 도 있습니다.
모든 타입에 관해서 모두 나열하지않았지만 기본적이 타입들에 대해서는 다본것같습니다.
BigInt라는 것도 있고 응용하면 여러 방법이 있겠지만 그건 그 때마다 공부해야할 것 같네요.