TypeScript 기본
🌟 JS의 문제점
자료형을 넘나드는 계산을 수행한다.따라서 다음과 같은 코드에서 에러를 보여주지 않는다.타입스크립트에서는 다음과 같이 에러를 보여준다.TS 컴파일 방법
npx tsc (파일이름).tstsc -w그러나 React에서 사용 시 애초에 typescript로 세팅하면 이러한 것들을 해주지 않아도 된다.🥕 기본 타입
기본 타입 지정 방법
const car: string = 'bmw';
const age: number = 30;
const a: number[] = [1, 2, 3];
const a2: Array<number> = [1, 2, 3];
const week1: string[] = ['mon', 'tue', 'wed'];
const week2: Array<string> = ['mon', 'tue', 'wed'];
week1.push(1);
기본적인 JS문법에서 변수명 뒤에 :를 이용하여 타입을 붙여준다.해당 변수에는 붙여준 타입의 데이터만 할당할 수 있다.따라서 위 코드에서 week1 배열에 숫자 타입 데이터를 push하면 에러가 난다.배열의 타입은 데이터타입[] 또는 Array<데이터타입>으로 결정할 수 있다.튜플 (Tuple)
let b: [string, number];
b = ['abc', 1];
b = [1, 'abc'];
b[0].toLowerCase();
b[1].toLowerCase();
튜플은 각 요소의 타입이 고정된 배열이다.튜플은 배열의 길이도 고정되어 있다.위 코드에서 b라는 배열의 0번 인덱스에는 string 타입만, 1번 인덱스에는 number 타입만 할당 될 수 있다.따라서 0번 인덱스에 number 타입을 할당하면 에러가 난다..toLowerCase()는 string 타입에만 사용할 수 있는 메소드 이므로 b[1](number 타입)에 해당 메소드를 사용하면 에러가 난다.Null, Undefined
const n: null = null;
const u: undefined = undefined;
null 또는 undefined 타입도 선언해줄 수 있다.Enum
Enum(열거형)은 연관된 아이템들을 묶어서 표현할 수 있는 수단이다.enum Os {
Window,
Ios,
Android,
}
let myComputer: Os;
myComputer = Os.Window;
myComputer = 'Window';
console.log(myComputer);
예시로 Os 라는 enum을 생성하면, 이를 타입처럼 사용할 수 있다.enum의 이름을 myComputer라는 변수에 타입으로 선언하면 해당 enum의 내용만 할당할 수 있다.따라서 문자열로 ‘Window’라고 적어서 할당한다고 해도 에러가 난다.그런데 여기서 myComputer를 콘솔에 찍었을 때 0이 나오는 이유는 해당 enum이 숫자 열거형이기 때문이다.
enum Os {
Window = 1,
Ios,
Android = 10,
}
console.log(Os.Window);
console.log(Os.Ios);
console.log(Os.Android);
enum의 각 키워드들이 값으로 갖는 숫자는 다음처럼 지정해줄 수 있다.지정되지 않으면 이전 값의 다음 값을 가진다.
enum Os {
Window = 'Window',
Ios = 'Ios',
Android = 'Android',
}
console.log(Os.Window);
console.log(Os.Ios);
console.log(Os.Android);
문자열 열거형으로 위처럼 선언하면 각각의 키워드가 문자열을 값으로 갖도록 할 수 있다.Any
모든 타입에 대하여 허용한다.기존 자바스크립트로 작동하던 서비스를 점진적으로 TS로 변환할 때 활용된다.let str: any = 'hi';
let num: any = 12;
let arr: any = [1, 2];
Object
객체는 다음처럼 타입을 정해 줄 수 있다.let jkeObj: { name: string; age: number; hobbies: string[] } = {
name: 'jke',
age: 27,
hobbies: ['Music', 'BasketBall'],
};
타입을 지정하는 부분에서는 , 대신 ;를 사용한다.Union
여러 타입 또는 값이 들어올 수 있도록 할 수 있다.
let unionType: number | string | number[] = 1;
unionType = 'jke';
unionType = 1;
unionType = [1, 2, 3];
let gender: 'M' | 'F' = 'M';
gender = 'F';
gender = 'T';
Void
function sayHello(): void {
console.log('hello');
}
함수가 아무것도 반환하지 않는 경우, void 타입으로 선언해줄 수 있다.위 코드처럼 선언해주면 해당 함수가 무언가를 return 하려고 할 경우 에러가 난다.해당 위치에 다른 타입을 선언하면 해당 타입만 리턴할 수 있다.Never
function showError(): never {
throw new Error();
}
function infLoop(): never {
while (true) {
}
}
함수의 return 타입으로 never 타입을 선언해줄 경우 항상 오류를 출력하거나 리턴 값을 절대로 내보내지 않음을 의미한다.이를 변수에 지정하면 never 가 아닌 타입은 할당할 수 없다.Unknown
let variable: unknown
variable = true
variable = 1
variable = 'string'
variable = {}
let anyType: any = variable
let booleanType: boolean = variable
let numberType: number = variable
let stringType: string = variable
let objectType: object = variable
unknown 타입은 any처럼 모든 타입을 허용한다.하지만 any는 타입 검사를 느슨하게 하여 애플리케이션에서 예기치 못한 문제가 발생할 가능성이 높다.unknown은 위 예제처럼 타입을 체크해주기 때문에 any보다 사용이 권장된다.🔦 Advanced Type
literal type
범용적인 string, number 등의 타입이 아니라 정확한 값을 타입으로 지정할 수 있다.const를 사용해 number나 string 등을 선언하면 literal type으로 추론된다.let age:3 = 3;
age = 5;
let name:"jke" = "jke";
name = "jkejkejke"
const age = 1;
const name = "jke"
as const
타입을 literal로 정확히 지정할 때 사용한다.이렇게 지정하면 상수로 지정한 값을 다른 파일에서 작성할 때도 볼 수 있어 편하다.const numbers = [1,2,3]
const numbers = [1,2,3] as const
const obj = {x:1, y:2}
const obj = {x:1, y:2} as const
Generic
타입을 인자처럼 활용할 수 있다.아래 상황에서는 해당 함수에 어떤 타입의 array가 들어올 지 모르는 상황이지만 array는 number의 array로 정의되어 있다.function map(array:number[], callback:(...args:any[]) => any;) {
const result = [];
for(const element of array){
result.push(callback(element));
};
return result;
}
map([1,2,3,4], x => x + 1);
map(["hello", "world"], x => x.toUpperCase());
이렇게 되면 문자열로 된 array를 map 함수에 인자로 넣어 사용하고 싶을 경우 또 다른 map 함수를 만들어주어야 한다.이와 같은 상황을 해결하기 위해 Generic을 사용할 수 있다.function map<T>(array:T[], callback:(...args:any[]) => any;) {
const result = [];
for(const element of array){
result.push(callback(element));
};
return result;
}
map<number>([1,2,3,4], x => x + 1);
map<string>(["hello", "world"], x => x.toUpperCase());
이렇게 하면 map함수를 사용할 때에 타입을 받아 그 타입이 array의 타입으로 지정되도록 할 수 있다.T는 임의의 이름이고 다른 이름을 사용해도 된다.keyof
객체 타입에서 key만 추출하는 방법이다.type People = {name: string, age:number, gender:"male" | "female", hobby:string};
type KeyOfPeople = keyof People;
const key:KeyOfPeople = 'name';
const key2:KeyOfPeople = 'email';
주의할 점은 object에 쓰는 것이 아니라 type에 쓰는 것이다.typeof
객체 등 값에서 타입을 추출하는 방법이다.const jke = {
name:"jke",
age:27,
gender:"male",
hobby:"basketball"
};
type People = typeof jke;
type KeyOfPeople = keyof typeof jke;
narrowing
if문 등을 사용하여 타입의 범위를 좁히는 방법이다.function toUpper(arg:string | number){
arg.toUpperCase()
}
function toUpper(arg:string | number){
if(typeof arg === "string"){
arg.toUpperCase()
}
}
function addFive(num?:number){
return num + 5;
}
function addFive(num?:number){
if(num){
return num + 5
} else {
throw new Error("Argument num is not a number")
}
}
🪃 Interface
Type을 변수에 넣어서 사용
타입 자체를 변수에 넣어서 사용할 수 있다.
type numOrStr = string | number;
let data: numOrStr = 1;
data = '1';
let typeArr: numOrStr[] = [1, '2', 3, '4'];
type grade = 'A' | 'B' | 'C' | 'D' | 'E';
const jkeGrade: grade = 'A';
기본 사용법
TS에서 복잡한 객체를 사용할 때 Interface 사용한다.Interface는 type과 다르게 객체에만 사용할 수 있다.일반 Type과 구분하기 위하여 첫글자를 대문자로 사용한다.interface User {
name: string;
id: string;
age: number;
isMember: boolean;
}
const jkeInfo: User = {
name: 'jke',
id: 'j56237',
age: 27,
isMember: true,
};