타입스크립트 부수기!
JS문법 그대로 TS에서 사용가능
타입스크립트 이용방법
변수에 타입지정가능
let 이름:string = 'kim';
이름 = 123; //에러가 남 string타입만 올 수 있기 때문에
변수에 [실드]를 씌우는 것입니다.
let age:number = 30;
let isAdult:boolean = true;
let a:number[] = [1,2,3];
let a2:Array<number> = [1,2,3]; //이렇게 써도 됨
let week1:string[] = ['mon','tue','wed'];
let week2:Array<string> = ['mon','tue','wed'];
타입스크립트 갓 배운 사람들은 모든 곳에 다 타입지정을 한다.
그런데 타입지정은 원래 자동으로 됩니다. 타입지정 문법 생략가능
let 회원들 = 'park' //이렇게 하면 무조건 회원들:string 이 되어있는것입니다.
let 회원 :number | string = 123; //문자 또는 숫자 들어갈 수 있음
Union Type
이라고 합니다.
let 회원들 :(number | string)[] = [1,'2',3]; //숫자 또는 문자 입력가능
let 회원들 : number | string[] = [1,2,3]; //이렇게 쓰면 숫자(1,2,3), ['1','2','3'] 가능하다는 뜻.
let 오브젝트 :{ a :string | number } = { a :'123' }
any
let 이름 :any;
이름 = 123;
이름 = [];
모든 자료형을 허용해주는 대신 타입스크립트를 쓰는 의미가 없어집니다.
이건 타입실드 해제문법입니다. '이름'이라는 변수의 실드를 해제시켜라 라는 뜻입니다.
그래서 타입관련 버그가 나도 잡아주질 않습니다.
unknown
let 이름 :unknown;
이름 = 123;
이름 = {};
모든 자료형을 허용해줍니다. any와 유사해보입니다.
하지만 unknown타입이 any보다 안전한 이유는
let 이름 : unknown;
이름 = 123;
이름 = {};
let 변수1 :string = 이름; //지금 이름이라는 변수는 {}(object)이기때문에 오류가 난다.
let 이름 : any;
이름 = 123;
이름 = {};
let 변수1 :string = 이름; //하지만 any를 쓰는 순간 모든 실드는 해제됩니다.
function 함수(x :number) : number {
return x * 2
}
함수(6)
함수는 파라미터, return값 타입지정 가능
함수에서 void타입
활용가능. 어떤값도 return하고 싶지 않을 때 (return이 없을 경우)
실수로 뭔가 return하는 걸 사전에 막을 수 있습니다.
파라미터가 옵션일 경우엔
파라미터변수?:타입
function 함수(x? :number) :void {
}
함수()
?연산자는 들어올 수도 있다~
라는 뜻이긴 한데
변수? :number는
변수 :number | undefined 와 같습니다.
❗️예를 들어 이런 함수가 있다고 생각해봅시다❗️
함수에 숫자 또는 문자를 집어넣으면 + 1 해주는 함수입니다.
function 내함수(x :number | string){
return x + 1 //에러남
}
근데 이런 에러가 납니다.
Operator '+' cannot be applied to types 'string | number' and 'number'
string | number 같은 union type 에는 일반적으로 조작을 못하게 막아놔서 그렇습니다.
이런 메세지를 보면
1. 타입을 하나로 Narrowing 해주거나
2. Assert 해주거나 둘 중 하나 해주면 됩니다.
Type Narrowing
if문 등으로 타입을 하나로 정해주는 것을 뜻합니다.
function 내함수(x :number | string){
if (typeof x === 'number') {
return x + 1
}
else if (typeof x === 'string') {
return x + 1
}
else {
return 0
}
}
if문과 typeof 키워드로 현재 파라미터의 타입을 검사해서
"이게 'number'타입일 경우 이렇게 해주세요~"
"이게 'string'타입일 경우 이렇게 해주세요~"
이렇게 코드를 짜야 정상적으로 사용이 가능합니다.
타입스크립트는 타입이 애매한 걸 싫어해서 귀찮아도 해야합니다.
타입이 확실하지 않을 때 생기는 부작용을 막기위한 장치라고 보시면 됩니다.
그런데 또 함수 안에서 if문을 쓸 때 마지막에 else {} 이게 없으면 에러가 납니다.
return 하지않는 조건문이 있다면 나중에 버그가 생길 수 있어서 에러를 내주는 것입니다.
assertion 문법
function 내함수(x :number | string){
let array :number[] = [];
array[0] = x as number;
}
내함수
let user:object;
user = {
name : 'xx',
age : 30
}
console.log(user.name)//이렇게 하면 오류가 납니다.
오류가 나는 이유: object에 특정 속성값에 대한 정보가 없기때문에..! 이렇게 프로퍼티를 정해서 객체를 표현하고자 할 때는 interface를 사용합니다.
interface User {
name : string;
age : number;
}
let user : User = {
name : 'xx',
age : 30
}
console.log(user.age) //에러가 발생하지 않습니다.
읽기전용입니다. 값의 접근은 할 수 있지만 수정은 불가능 합니다.
interface User {
name : string;
age : number;
gender? : string;
readonly birthYear : number;
}
let user : User = {
name : 'xx',
age : 30,
birthYear : 2000,
}
user.age = 10;
user.gender = "female"
user.birthYear = 1990; //오류가 납니다.
console.log(user.age)
birthYear에서 오류가 나는건 readonly가 읽기 전용 속성이어서 그렇습니다. 수정을 못한다는 얘기입니다.
생성할 때만 할당 가능하고 이후에는 수정하지 못합니다.
interface User {
name: string;
age: number;
}
function join(name: string, age: string): string;
function join(name: string, age: number): User;
function join(name: string, age: number | string): User | string {
if (typeof age === "number") {
return {
name,
age,
};
} else {
return "나이는 숫자로 입력해주세요.";
}
}
const sam: User = join("Sam", 30);
const jane: string = join("Jane","30");
함수 오버로드를 해주어서 에러를 잡습니다.
const userName1 = "Bob";
let userName2 = "Tom";
const로 정의한 userName1은 "Bob"만 쓸 수 있는데,
let으로 정의한 userName2는 어떤 string이던 가능하다.
const userName1 같은 타입을 문자열 리터럴 타입이라고 부릅니다.
interface Car {
name: "car";
color: string;
start(): void;
}
interface Mobile {
name: "mobile";
color: string;
call(): void;
}
function getGift(gift: Car | Mobile) {
console.log(gift.color);
if (gift.name === "car") {
gift.start();
} else {
gift.call();
}
}
마지막에 if문을 사용했는데 검사할 항목이 많으면 switch를 쓰는 것이 좋습니다.
interface Car {
name: string;
start(): void;
}
interface Toy {
name: string;
color: string;
price: number;
}
const toyCar: Toy & Car = {
name : "타요",
start() {},
color: "blue",
price: 1000,
};
&를 사용해서 두 가지 타입을 합칠 수도 있습니다.
그대신 안에는 두가지 타입에 있는 모든 걸 다 적어야 에러가 나지 않습니다.
제네릭을 이용하면 클래스나 함수, 인터페이스를 다양한 타입으로 재사용할 수 있습니다. 선언할 때는 그냥 타입 파라미터만 적어주고 생성하는 시점에서 사용하는 타입을 결정하는 겁니다.
function getSize<T>(arr: T[]): number {
return arr.length;
}
const arr1 = [1,2,3];
getSize<number>(arr1); //3
<T>를 타입파라미터라고 합니다.
어떤 타입을 전달받아서 이 함수에서 사용할 수 있게 합니다.
사용하는 쪽에서 타입을 결정해줍니다.
interface Mobile<T> {
name: string;
price: number;
option: T;
}
const m1: Mobile<object> = {
name: "s21",
price: 1000,
option: {
color: "red",
coupon: false,
},
};
const m2: Mobile<string> = {
name: "s20",
price: 900,
option: "good",
};
option에서 어떤 데이터를 사용할지 모르기 때문에 이럴 때 제네릭을 쓸 수 있습니다.
interface User {
id: number;
name: string;
age: number;
gender: "m" | "f";
}
type UserKey = keyof User; // 'id' | 'name' | 'age' | 'gender'
const uk:UserKey = "id";
interface User {
id: number;
name: string;
age: number;
gender: "m" | "f";
}
//interface User {
// id?: number;
// name?: string;
// age?: number;
// gender?: "m" | "f";
//}
let admin: Partial<User> = {
id: 1,
name: "Bob",
job: "" // 에러납니다. User에 없기때문이죠.
};
모든걸 옵션으로 바꿔줌.
모든 걸 필수로 바꿔줌.
interface User {
id: number;
name: string;
age?: number;
}
let admin: Required<User> = {
id: 1,
name: "Bob",
age: 30; //이걸 안적으면 오류가 남. 모두 필수로 바꼈기때문에
};