TypeScript 중요한거 모아 정리해보기
타입스크립트란 ?
-
TypeScript는 JavaScript에 추가적인 구문을 추가하여 editor와의 단단한 통합을 지원합니다. editor에서 초기에 오류를 잡을 수 있습니다.
-
TypeScript 코드는 JavaScript가 실행되는 모든 곳(브라우저, Node.js 또는 Deno 및 앱 등)에서 JavaScript로 변환될 수 있습니다.
-
TypeScript는 JavaScript를 이해하고 타입 추론(type inference)을 사용하여 추가 코드 없이도 훌륭한 도구를 제공합니다.
Interface
- 인터페이스는 일반적으로 타입 체크를 위해 사용되며 변수, 함수, 클래스에 사용할 수 있습니다.
- 인터페이스는 여러가지 타입을 갖는 프로퍼티로 이루어진 새로운 타입을 정의하는 것과 유사합니다.
- 인터페이스에 선언된 프로퍼티 또는 메소드의 구현을 강제하여 일관성을 유지할 수 있도록 하는 것입니다.
- 인터페이스는 프로퍼티와 메소드를 가질 수 있다는 점에서 클래스와 유사하나 직접 인스턴스를 생성할 수 없고 모든 메소드는 추상 메소드입니다.
예제를 보며 살펴보겠습니다.
type Score = 'A' |'B'|'C'|'F';
interface User {
name: string;
age : number;
gender? : string; // ?표시가 있으면 있어도 되고 없어도 된다.
readonly birtYear : number;
[grade: number] : Score;
}
let user: User = {
name: 'xx',
age: 30,
birtYear: 2000,
1 : 'A',
2 : 'B',
3 : 'C'
}
user.age = 50;
console.log(user.age); // 50
interface Add {
(num1: number, num2: number): number;
}
const add: Add = (x, y) => x + y;
console.log(add(23, 20)); // 43
interface IsAdult {
(age: number): boolean;
}
const a:IsAdult = (age) => {
return age > 19;
}
console.log(a(20)); // true
Implements
- implements을 사용하여 클래스가 특정 인터페이스를 충족하는지 확인할 수 있습니다.
-
클래스를 올바르게 구현하지 못하면 오류가 발생합니다.
- object를 interface로 typing하듯, class도 interface로 typing한다고 생각하면 됩니다.
- implements 는 부모의 메소드나 변수를 그대로 가져다 쓰는게 아닌 반드시 오버라이드 해서 사용 해야 한다.
interface Car {
color: string;
wheels: number;
start(): void;
}
class Bmw implements Car {
color = "red";
wheels = 3;
start(){
console.log('go.....');
}
}
class Benz implements Car {
color;
wheels = 4;
constructor(c:string) {
this.color = c;
}
start(){
console.log('go.....');
}
}
const b = new Benz('white');
const e = new Bmw();
e.start(); // 'go.....'
extends (클래스 상속) -> abstract가 아닌 일반 class extends를 다룬다.
부모에서 선언된 메소드 혹은 변수를 자식은 모두 상속 받아 그대로 사용 할 수 있다.
interface Car {
color: string;
wheels: number;
start(): void;
}
interface Audi extends Car {
door: number;
stop(): void;
}
const audi: Audi = {
color: "blue",
wheels: 4,
door: 3,
start() {
console.log("heelo");
},
stop() {
console.log("stop")
}
}
두개 클래스 상속
interface FIFA {
team: string;
ball: number;
start(): void;
}
interface Soccer {
name: string;
}
interface FIFASoccer extends FIFA, Soccer {
bigEar: number;
}
const theSoccer: FIFASoccer = {
team: 'FC Seoul',
ball: 1,
start(){
console.log('fifa');
},
name: 'pkb',
bigEar: 5,
}
함수 타입
-
함수에서 아무것도 return 해주지 않을 땐 void를 타입으로 써준다.
function add(num1: number, num2: number): void { // return num1 + num2; console.log(num1 + num2); }
-
return이 있을 땐 타입에 맞게 써준다.
function isAdult(age: number):boolean { return age > 19; }
-
인터페이스처럼 함수의 매개변수도 옵셔널로 지정할 수 있습니다.
function hello(name?: string) { //여기서 name은 선택적 매개변수 return `Hello, ${name || "world"}`; } const result = hello();
-
나머지 매개변수의 타입 작성법
function add(...nums: number[]) { return nums.reduce((result, num) => result + num, 0); } add(1, 2, 3); // 6
this와 관련된
interface User {
name: string;
}
const Sam: User = {name: 'pkb'}
function showName(this:User, age: number, gender:'m'|'f') {
console.log(this.name, age, gender);
}
const a = showName.bind(Sam);
a(30, 'm'); // "pkb", 30, "m"
-
여기서 this는 사용하는 방법에 따라서 달라집니다. 지금 위 코드에서는 bind메소드를 통해 this 를 Sam 객체로 강제하고 있습니다.
-
타입스크립트에서는 this를 쓰고 타입을 정해줘야합니다. 만약 매개변수가 있으면 첫번 째 인수로 적어줍니다.
interface User {
name: string;
age: number;
}
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 pkb: string = join("pkb", "30");
위 코드를 보면 아무 문제가 없는 것처럼 보이지만 sam 과 pkb에서 오류가 납니다.
이유는 sam이 User 객체를 반환한다는 확신이 없기 때문입니다. 즉 string을 반환할수도 있다고 판단하기 때문입니다.
위 코드에서는 age매개변수의 타입에 따라 결과 값이 달라지고 있습니다. 이럴때는 오버로드를 사용합니다. 함수 오버로드는 전달받은 매개변수의 갯수나 타입에 따라 다른 동작을 하게 하는 것을 의미합니다. 여기 이 함수 위에 똑같은 모습으로 작성을 해주시면 됩니다.
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);
console.log(sam); // {"name": "sam","age": 30}
const pkb: string = join("pkb", "30");
console.log(pkb); // "나이는 숫자로 입력해주세요."
Literal Types
-
TypeScript에는 문자열과 숫자, boolean 세 가지 리터럴 타입이 있는데 이를 사용하면 문자열이나 숫자에 정확한 값을 지정할 수 있습니다.
- 문자열 Literal Types
const userName1 = "Bob"; // 이렇게 정해진 스트링값을 가진 것을 문자열 리터럴 타입이라함 let userName2: string | number = "Tom"; userName2 = 3; type Job = "police" | "developer" | "teacher"; interface User { name: string; job: Job; } const user: User = { name: "Bob", job: "developer" // 위에 Job에서 선언된것만 사용할 수 있다. }
- 숫자형 Literal Types
interface HighSchoolStudent { name: string; grade: 1 | 2 | 3; // 학년은 1, 2, 3만 사용할 수 있다. }
Union Types
-
유니온 타입(Union Type)이란 자바스크립트의 OR 연산자(
||
)와 같이'A' 이거나 'B'이다
라는 의미의 타입입니다.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(); } }
Intersection Types
-
인터섹션 타입(Intersection Type)은 여러 타입을 모두 만족하는 하나의 타입을 의미합니다.
interface Car { name: string; start(): void; } interface Toy { name: string; color: string; price: number; } const toycar: Toy & Car = { name: "타요", // Toy와 Car 엔퍼서티를 다 적어주어야함 start(){}, color: "red", price: 5, }
Class
-
Typescript 클래스는 클래스 몸체에 클래스 프로퍼티를 사전 선언하여야 합니다.
class Car { color: string; // js에서는 이 코드 color: string를 안써줘도 상관없지만 ts에서는 써줘야함 constructor(color:string) { this.color = color; } start(){ console.log('start'); } } const bmw = new Car("red");
-
Typescript 클래스에서는 사용할 수 있는 접근제한자(Access modifier)
-
public - 자식 클래스, 클래스 인스턴스 모두 접근 가능
class Car { // color: string;프로퍼티를 미리 선언하지않고 하는방법으로는 public과 readonly 있다. constructor(public color:string) { this.color = color; } start(){ console.log('start'); } } const bmw = new Car("red");
class Car { public name: string = "car"; color: string; constructor(color: string) { this.color = color; } start() { console.log("start"); } } class Bmw extends Car { constructor(color: string) { //public을 통해 super매소드 사용할수있다. super(color); } showName() { console.log(super.name); } } const z = new Bmw("black");
-
protected - 자식 클래스에서 접근가능 public과 다른점으로는 자식클래스 내부에서는 참조할 수 있으나 클래스 인스턴스로는 참조할 수 없다.
class Car { protected name: string = "car"; color: string; constructor(color: string) { this.color = color; } start() { console.log("start"); console.log(this.name); } } class Bmw extends Car { constructor(color: string) { //public을 통해 super매소드 사용할수있다. super(color); } showName() { console.log(super.name); } } const z = new Bmw("black"); // console.log(z.name); 에러가 발생한다. protected는 클래스 인스턴스로는 참조 X
-
private - 해당 클래스 내부에서만 접근가능 private 대신 # 사용가능
class Car { private name: string = "car"; color: string; constructor(color: string) { this.color = color; } start() { console.log("start"); console.log(this.name); // private로 인해 여기서만 사용할수있다. } } class Bmw extends Car { constructor(color: string) { . super(color); } showName() { // console.log(super.name); private로 인해 사용불가 } } const z = new Bmw("black");
-
readonly - 읽기전용
class Car { readonly name: string = "car"; color: string; constructor(color: string) { this.color = color; } start() { console.log("start"); console.log(this.name); } } class Bmw extends Car { constructor(color: string) { . super(color); } showName() { console.log(super.name); } } const z = new Bmw("black"); console.log(z.name); // z.name = 'zzz4'; readonly에 의해서 읽기 전용이라 변경 불가
-
static - static을 써주면 정적 변수를 만들 수 있다. this가 아니라 클래스명을 적어주어야합니다.
class Car { name: string = "car"; color: string; static wheels = 4; constructor(color: string) { this.color = color; } start() { console.log("start"); console.log(Car.wheels); // 클래스명을 적어주어야함 } } class Bmw extends Car { constructor(color: string) { super(color); } showName() { console.log(super.name); } } const z = new Bmw("black"); console.log(Car.wheels); // 클래스명을 적어주어야함
-
추상 class - 클래스 앞에
abstract
적어주어서 사용할 수 있습니다.- new를 이용하여 객체를 만들수는 없습니다. 오직 상속을 통해서만 사용가능합니다.
- 추상 클래스는 오직 다른 클래스가 상속받을 수 있는 클래스입니다. 하지만 직접 새로운 인스턴스를 만들 수는 없습니다.
abstract class Car { color: string; constructor(color: string) { this.color = color; } start() { console.log("start"); } abstract doSomething(){} //이렇게 abstract을 써주면 상속 받는쪽에서 구체적인 기능을 구현해줘야함 } // const car = new Car("red") 불가능 class Bmw extends Car { constructor(color: string) { super(color); } doSomething() { alert(3); // 이렇게 여기에 구체적인 기능을 구현해줘야 에러가 안남. } } const z = new Bmw("black");
-
Generic
-
Generic 이용하면 클래스나 함수 인터페이스를 다양한 타입으로 재사용할 수 있습니다.
-
선언할 때는 타입 파라미터만 적어주고 생성하는 시점에 사용하는 타입을 결정하는 것입니다.
function getSize<T>(arr: T[]): number { return arr.length; } const arr1 = [1, 2, 3]; getSize<number>(arr1); // 3 const arr2 = ["a", "b", "c"]; getSize<string>(arr2); // 3 const arr3 = [false, true, true]; getSize<boolean>(arr3); // 3
-
옵션으로 사용할 때
interface Mobile<T> { name: string; price: number; option: T; } const m1: Mobile<object> = { name: "pkb", price: 1000, option: { color: "red", coupon: false, } } const m2: Mobile<string> = { name: "pkb", price: 1000, option: "hello", }
-
확장으로 사용 할 때
interface User { name: string; age: number; } interface Car { name: string; color: string; } interface Book { price: number; } const user: User = {name: "A", age: 3}; const car: Car = {name: "bmw", color: "red"}; const book: Book = { price: 1000 }; function showLook<T extends { name:string }>(data:T): string { return data.name; } showLook(user); showLook(car); // showLook(book); book에는 name이 없어서 에러남
-
Utility Types
-
keyof - key값들을 유니온 형태로 받을 수 있습니다.
interface User { id: number; name: string; age: number; gender: "m" | "f"; } type UserKey = keyof User; // 'id' | 'name' | 'age' | 'gender' const uk: UserKey = "age"; const uk1: UserKey = "name";
-
Partial
은 프로퍼티를 모두 옵션으로 바꿔줍니다. 그래서 일부만 사용하는게 가능합니다.
interface User {
id: number;
name: string;
age: number;
gender: "m" | "f";
}
let admin:Partial<User> = { // 원래는 age, gender를 포함해야하는데 Partial을 통해 일부만 사용함.
id: 1,
name: 'BOD',
}
-
Required
은 프로퍼티를 필수로 바꿔줍니다. interface User { id: number; name: string; age?: number; } let people: Required<User> = { //이렇게 Required를 써주면 age도 필수가 되버린다. id: 112, name: "pkb", age: 22, }
-
Record<K,T>은 여기서 K는 key이고 T는 type입니다.
interface Score22 { "1" : "A" | "B" | "C" | "D"; "2" : "A" | "B" | "C" | "D"; "3" : "A" | "B" | "C" | "D"; "4" : "A" | "B" | "C" | "D"; } const score: Score22 = { 1: "A", 2: "B", 3: "C", 4: "D", } // 이부분을 Record를 활용해보면 type Grade = '1'|'2'|'3'|'4'; type Score ="A" | "B" | "C" | "D" | "F"; const score: Record<Grade, Score> = { 1: "A", 2: "B", 3: "C", 4: "D", }
-
Pick<T,K>은 T타입에서 K프로퍼티만 골라서 사용합니다.
interface User { id: number; name: string; age: number; gender: "M" | "W"; } const admin: Pick<User, 'id' | 'name'> = { id: 0, name: "bob", };
-
Omit<T,K> T타입에서 K프로퍼티를 제외하고 사용합니다.
interface User { id: number; name: string; age: number; gender: "M" | "W"; } const admin: Omit<User, 'age' | 'gender'> = { id: 0, name: "bob", };
-
Exclude<T1,T2> Omit은 프로퍼티들을 제외하는 것이고 Exclude는 타입으로 제외를 합니다. T1중에서 T2와 겹치는것을 제외합니다.
type T1 = string | number | boolean; type T2 = Exclude<T1, number | string> //boolean만 사용가능
-
NonNullable
null을 제외한 타입을 생성합니다. undefined도 포함시켜서 제외시킵니다. type t1 = String | null | undefined | void; type t2 = NonNullable<t1>; //이렇게 해주면 string 과 void만 사용가능
댓글남기기