type Alias와 String Literal Type, union Types, Disciminated Unions, Enum , type interferece에 대해 알아보자!
// Text란 타입은 없지만 사용자가 text 타입아래와 같이 정의하면 text란 타입은 문자열의 타입이 된다.
type Text = string;
const address: Text = "no War"
const test: Text = 'hello world!'
type Num = number; // Num이라고 문자열 타입도 정의가능하다.
//object property type
type Student = {
name: string;
age: number;
};
const student: Student = {
name: 'Nowar',
age: 2022,
};
const student: Student = {
animal: 'dog' // name 프로퍼티가 없기 때문에 error 발생, name의 문자열과 ,age숫자 타입가 있어야 에러발생하지 않음!
}
type Name = 'name';
let clubName: name;
myName = 'name';
myName = 'chelsi'; // 'name'이 아니기 때문에 error 발생한다.
type JSON = 'json';
const json: JSON = 'json';
type Bool = true;
const isCat: Bool = true;
const isCat: Bool = false; // true 가 아니기 때문에 error 발생
or
과 비슷한 역할을 한다.type Direction = 'left' | 'right' | 'up' | 'down';
function move(direction: Direction) {
console.log(direction);
}
move('right');
move('left');
move('hello world') // error : 위에서 설정한 4가지의 경우의 값을 제외한 경우 에러가 발생!
String literal type
과 조합하면 활용도가 높다.로그인의 상태를 리턴해주는 함수를 만든다고 가정해봅시다.
// login 의 함수로서 로그인이 성공하면 sucees, 실패하면 fail과 이유가 잇는 함수라고 해보자
type SuccessState = {
response: {
body: string;
}
}
type FailState = {
reason: string;
}
// 이렇게 만들어 줄 수 있겠지만 로그인의 타입을 아래와 같이 만들어줌으로서 type을 지정해서 관리 해줄 수 있다.
//before
function login():SuccessState | FailState {}
type LoginState = SuccessState | FailState;
// after: union type 적용 후
function login(id: string, password: string): LoginState {
// Promise<LoginState> 실제 프로젝트에서는 프로미스겠죠?
return {
response: {
body: 'logged in!',
},
};
}
union
타입에서 차별화되는 이름이 동일한 타입을 가지고 있으면서 간편하게 구분히 가능한 타입이라고 할 수 있다.//로그인이 성공했디고 가정하고 성공했을시 req.body를 출력해주고, 실패 했을 시 실패에 대한 이유가 나온다고 해보자!
// 리턴이 없기 때문에, void타입은 생략되어 있음!
function printLoginState(state: LoginState) {
//보편적으로는 아래처럼 사용해서 response있다면 성공의 경우 출력을 해주고 실패한 경우, 아래처럼 로직을 짤 수 있다.
if ('response' in state) {
console.log(`🚀 ${state.response.body}`);
} else {
// console.log(${state.response.body}) 이런 식으로 접근 하게 된다면,
//이 경우의 성공, 실패 두가지 경우 이므로 에러를 잡아주기는 한다.
console.log(`😇 ${state.reason}`);
}
}
//동일한 key 인 result를 각 성공 실패 상태마다 갖고 있지만, 어떤 state냐에 따라 다른 타입이 지정되도록 하여, 타입이 보장되면서 서로 다른 state를 만들 수 있다.
type SuccessState = {
result: 'success';
response: {
body: string;
};
};
type FailState = {
result: 'fail';
reason: string;
};
type LoginState = SuccessState | FailState;
function printLoginState(state: LoginState) {
state.result; // success or fail
if (state.result === 'success') {
console.log(`🚀 ${state.response.body}`);
} else {
console.log(`😇 ${state.reason}`);
}
}
}
&
과 비슷한 역할을 한다. // 아래과 같이 student 타입과 worker를 지정해줬다고 하자.
type Student = {
name: String;
score: number;
};
type Worker = {
empplyeeId: number;
work: () => void;
};
// 인턴쉽을 하는 근로자는 학생이면서 일하는 사람일 수 있다.
function internWork(person: Student & Worker) {
console.log(person.name, person.empplyeeId, person.work());
}
internWork({
name: "iam intern",
score: 8,
empplyeeId: 2342,
work: () => {},
});
Object.freeze({})
를 사용해서 외부에서 변경할 수 없는 객체를 지정할 수 있다.//javscript : Object.freeze()를 사용해서 집합을 묶어 불변한 객체를 관리 할 수 있다.
const MONDAY = 0;
const TUESDAY = 1;
const WEDNESDAY = 2;
const DAYS_ENUM = Object.freeze({ MONDAY: 0, TUESDAY: 1, WEDNESDAY: 2 });
const dayOfToday = DAYS_ENUM.MONDAY;
// 값을 할당시!
//enum Days {
// Monday = "Monday",
// Tuesday = "tuesday",
// Wednesday = "wed",
// Thursday = "thur",
// Friday = "fri",
// Saturday = "sat",
// Sunday = "sun",
//}
//할당을 따로 안 할 시,
enum Days {
Monday, // 0
Tuesday, // 1
Wednesday, // 2
Thursday, // 3
Friday, // ...
Saturday,
Sunday,
}
console.log(Days.Monday); // 0이 할당됨
let day = Days.Friday // 4
// 현재 day 변수는 Days(enum)타입을 가질 수 있는데 이 때,
// enum이 가지고 있는 타입을 임의로 지정할 수 있다.
day = Days.Friday;
day = 10; // 컴파일 에러가 발생하지 않음!
console.log(day);
대체방안으로 union Type을 대신하여 활용이 가능하다.
type Day = 'Monday' | 'Tuesday' | 'Wednesday' | 'Thursday' | 'Friday' | 'Saturday' | 'Sunday'
let dayOfWeek: Day = 'Monday'
enum
의 사용 예시type Errors = 'error message simple version' | 'error message complicated version' | 'error message complicated detail version';
// 이렇게 복잡한 union의 경우에는 아래처럼 enum으로 해줄 수 도 있지 않을까 생각한다. (엘리님 의견)
enum Errors {
Short: 'error message simple version' ,
Long: 'error message complicated version',
Detail: 'error message complicated detail version'
}
void
타입이라면 생략이 가능하나, 타입 추론을 사용하기는 지양하는 편이 좋다.let text = 'hello'; // 이경우 문자열이 할당하면 타입을 따로 명시하지 않으면, 타입은 문자열이라고 ts에서 타입을 추론함
text = "hello world";
text = 1; // error 발생 문자열로 추론했기 때문에.
// 함수의 매개변수에는 자동으로 any로 추론한다. 그러므로 type을 지정해주는 것이 좋다.
function print(message) {
console.log(message)
}
print('hello')
print(1)
parameter
의 타입으로 지속적으로 추론한다.function printStr(message = 'hi') {
console.log(message)
}
printStr('hello');
printStr(1); // error
number
타입이므로 return
값의 타입도 number
일 것이라고 추론한다.function add(x: number, y: number) {
return x + y;
}
// add 함수는 return 값을 number 타입으로 추론했따.
// 그 함수의 리턴 값을 변수에 담는다면, 그 변수 또한 number 타입이라고 추론한다.
//
const result = add(1, 2);
//하지만, 아래처럼 더욱 구체적으로 명시를 해주는 것이 좋을 것이다.
function add(x: number, y: number):number {
return x + y;
}
자바스립트 라이브러리와 같은 타입이 없는 자바스크립트와 연동이 되기 때문에 불가피하게 사용하게 될 경우를 위해 제공되어진다.
type을 장담하는 경우 사용 할 수 있으나 그래도 지양하는 것이 좋다.
// 아래와 같은 js함수가 있다고 하면 , 리턴은 문자열을 리턴하는 함수라고 있다고 하자
function jsStrFunc(): any {
return "hello";
}
// 내부적으로 문자열이 반환 되는 것을 알고 있고 아래의 result 변수에 담고 스트링의 메서드를 사용하고 싶다면 어떻게 해야할까?
const result = jsStrFunc();
//아래처럼 사용 가능하다!
console.log((result as string).length);
console.log((<string>result).length);
하지만 실제 함수 반환값이 hello의 문자열이 아닌 숫자를 반환한다면? 에러가 발생하고 undefined를 반환 할 것이다.
// 아래의 함수는 number 배열을 반환한거나 혹은 undefined반환 하는 함수라고 해보자
function findNumbers2(): number[] | undefined {
return undefined;
}
const numbers = findNumbers2();
numbers.push(2); // 😱 // 느낌표는 절대적으로 값이 있다고 확신하고 함! undefined될 수 없다고 장담하고 하는 것..
const numbers = findNumbers2()!; // 이처럼 함수에 느낌표를 붙이거나 아래의 느낌표를 붙여 사용 가능
numbers.push(3);
const numbers = findNumbers2();
numbers!.push(2)
// 이런식으로 장담하다고 하다보면, 어플리케이션이 죽을 수도 있기 때문에 가능하면 사용을 피하는 것이 좋을거 같다.