일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
31 |
- 코딩테스트
- 코드잇
- Cookie
- MySQL
- 프로그래머스
- 데이터베이스시스템
- JavaScript
- 코딩테스트준비
- 방송대
- 99클럽
- nestjs
- 중간이들
- redis
- 꿀단집
- 파이썬
- 자격증
- 항해99
- aws
- node.js
- 파이썬프로그래밍기초
- 엘리스sw트랙
- SQL
- 개발자취업
- HTML
- CSS
- TiL
- Git
- 방송대컴퓨터과학과
- Python
- 유노코딩
- Today
- Total
배꼽파지 않도록 잘 개발해요
[엘리스sw] 5주차 5일 - 인터페이스, 제네릭 본문
◆ Interface
◆ Generic
Interface
Interface란
Interface
· 일반적으로 변수, 함수, 클래스에 타입 체크를 위해 사용된다.
· 직접 인스턴스를 생성할 수 없고, 모든 메소드가 추상 메소드이다.
· 추상 클래스의 추상 메소드와 달리 abstract 키워드는 사용할 수 없다.
· ES6은 인터페이스를 지원하지 않지만 TypeScript는 인터페이스를 지원한다.
Interface를 사용하는 이유
· 타입의 이름을 짓고 코드 안의 계약을 정의한다.
· 프로젝트 외부에서 사용하는 코드의 계약을 정의한다.
· 다음과 같은 범주에 대해 계약을 정의할 수 있다.
- 객체의 스펙 (속성과 속성의 타입)
- 함수의 파라미터
- 함수의 스펙 (파라미터, 반환 타입 등)
- 배열과 객체에 접근하는 방식
- 클래스
Interface 기본 예제
· Interface를 추가하여 함수 매개변수 프로퍼티를 정의할 수 있다.
· 정의한 프로퍼티 값을 누락하거나 정의하지 않는 값을 인수로 전달시 컴파일 에러가 발생한다.
function sayName(obj: { name: string }) {
console.log(obj.name);
}
let person = { name: "june" };
sayName(person);
interface Person {
name: string
}
function sayName(obj: person) {
console.log(obj.name);
}
let person = { name: "june" };
sayName(person);
Person 객체의 구조를 변경하기로 결정한 경우 인터페이스만 업데이트하면 됨.
Properties
Properties
컴파일러는 프로퍼티의 두 가지 요소를 검사한다.
- 필수요소 프로퍼티의 유무
- 프로퍼티 타입
아래 예약어로 프로퍼티를 세밀하게 컨트롤 할 수 있다.
- ? (Optional Properties)
- readonly (Readonly properties)
Optional Properties
· 프로퍼티 선언 시 이름 끝에 ?를 붙여서 표시한다.
· 인터페이스에 속하지 않는 프로퍼티의 사용을 방지하면서, 사용 가능한 프로퍼티를 기술할 때 사용한다.
· 객체 안의 몇 개의 프로퍼티만 채워 함수에 전달하는 "option bags" 같은 패턴에 유용하다.
interface Person {
name: string;
age?: number; // 물음표로 옵셔널 프로퍼티임을 표시함
}
function printPerson(person: Person) {
console.log(`Name: ${person.name}`);
if (person.age !== undefined) {
console.log(`Age: ${person.age}`);
}
}
let john: Person = { name: "John" };
let jane: Person = { name: "Jane", age: 25 };
printPerson(john);
// Name: John
printPerson(jane);
// Name: Jane
// Age: 25
readonly properties
· 객체가 처음 생성될 때만 값 설정이 가능하고, 이후 수정이 불가능하다.
· 프로퍼티 이름 앞에 readonly를 붙여 사용한다.
interface Car {
readonly brand: string; // 수정 불가
model: string;
}
let myCar: Car = { brand: "Toyota", model: "Camry" };
myCar.brand = "Honda";
// error TS2540: Cannot assign to 'brand' because it is a read-only property.
console.log(`Brand: ${myCar.brand}`)
// Brand: Toyota
readonly vs const
· readonly 와 const 의 공통점 : 생성 후에 배열을 변경하지 않음을 보장한다.
· 변수는 const를 사용하고 프로퍼티는 readonly를 사용한다.
const
const numbers: number[] = [1, 2, 3];
numbers.push(4);
console.log(numbers)
// [1, 2, 3, 4 ]
numbers = [3, 5, 7];
console.log(numbers)
// error TS2588: Cannot assign to 'numbers' because it is a constant.
readonly
let arr: number[] = [1, 2, 3, 4];
let readonly_arr: ReadonlyArray<number> = arr;
// 가능
arr[0] = 12;
arr.push(5);
arr.length = 100;
// 불가능
readonly_arr[0] = 12;
readonly_arr.push(5);
readonly_arr.length = 100;
Interface types
TypeScript에서 인터페이스는 함수, 클래스에서 사용할 수 있다.
함수
- JavaScript 객체가 가질 수 있는 넓은 범위의 형태를 기술한다.
- 프로퍼티로 객체를 기술하는 것 외에도, 인터페이스는 함수 타입을 설명한다.
클래스
- 클래스가 특정 통신 프로토콜을 충족하도록 명시적으로 강제한다.
- C#과 Java 같은 언어에서 일반적으로 인터페이스를 사용하는 방법과 동일하다.
function type
· 함수의 인자의 타입과 반환 값의 타입을 정의한다.
· 함수의 타입을 정의할 때에도 사용한다.
type AddFunction = (num1: number, num2: number) => number;
const add: AddFunction = (num1, num2) => num1 + num2;
const result: number = add(3, 5);
console.log(result); // 출력: 8
class type
· 클래스가 특정 계약(contract)을 충족하도록 명시적으로 강제한다.
interface Shape {
calculateArea(): number;
}
class Circle implements Shape {
radius: number;
constructor(radius: number) {
this.radius = radius;
}
calculateArea() {
return Math.PI * this.radius ** 2;
}
}
const circle: Shape = new Circle(5);
console.log(circle.calculateArea()); // 78.54
Shape 인터페이스는 숫자를 반환하는 calculateArea 메소드를 사용하여 계약을 정의합니다.
Circle 클래스는 필수 calculateArea 메소드를 제공하여 Shape 인터페이스를 구현합니다.
Circle 클래스의 인스턴스가 생성되어 Shape로 사용되며, 이는 `Shape`에 의해 정의된 계약을 준수함을 나타냅니다.
interface 확장
· 클래스와 마찬가지로 인터페이스도 인터페이스 간의 확장이 가능하다.
interface Person {
name: string;
age: number;
}
interface Employee extends Person {
employeeId: string;
department: string;
}
const employee: Employee = {
name: 'John Doe',
age: 30,
employeeId: '123',
department: 'IT',
};
hybrid type
· 자바스크립트의 유연하고 동적인 타입 특성에 따라 인터페이스도 여러 가지 타입을 조합할 수 있다.
· 아래 코드와 같이, 함수 타입이면서 객체 타입을 정의할 수 있는 인터페이스도 구현할 수 있다.
interface User {
name: string;
age: number;
greet(): void;
}
const myUser: User = {
name: 'Alice',
age: 25,
greet() {
console.log(`Hello, my name is ${this.name} and I'm ${this.age} years old.`);
}
};
myUser.greet();
디자인 패턴 (stratefy pattern)
interface를 활용한 디자인 패턴
객체가 할 수 있는 행위들을 전략(strategy)으로 만들어두고, 동적으로 행위의 수정이 필요한 경우 전략을 바꾸는 것만으로 수정이 가능하도록 만든 패턴
Generic
Generic 개념
· 데이터타입을 일반화하는 것
· 정적 type 언어는 클래스나 함수를 정의할 때 type을 선언해야 한다.
ex. C언어는 int type 변수를 선언하면 정수형 값만 할당할 수 있다.
· Generic은 코드를 작성할 때가 아니라 코드가 수행될 때 타입을 명시한다.
· 코드를 작성할 때 식별자를 써서 아직 정해지지 않은 타입을 표시한다.
- 일반적으로 식별자는 T, U, V ...를 사용한다.
- 필드 이름의 첫 글자를 사용하기도 한다.
Generic을 사용하는 이유
- 재사용성이 높은 함수와 클래스를 생성할 수 있다.
- 여러 타입에서 동작이 가능하다. (한번의 선언으로 다양한 타입에 재사용할 수 있다.)
- 코드의 가독성이 향상된다. - 오류를 쉽게 포착할 수 있다.
- any 타입을 사용하면 컴파일 시 타입을 체크하지 않는다.
- 타입을 체크하지 않아 관련 메소드의 힌트를 사용할 수 없다.
- 컴파일 시에 컴파일러가 오류를 찾지 못한다. - Generic도 any처럼 미리 타입을 지정하지는 않지만, 타입을 체크해 컴파일러가 오류를 찾을 수 있다.
Generic을 사용해 function과 class 만들기
function
function echo<T>(value: T): T {
return value;
}
const resultString: string = echo("Hello, TypeScript!");
const resultNumber: number = echo(42);
console.log(resultString); // Hello, TypeScript!
console.log(resultNumber); // 42
class
class Box<T> {
constructor(private value: T) {}
getValue(): T {
return this.value;
}
setValue(newValue: T): void {
this.value = newValue;
}
}
const stringBox = new Box("Hello");
const numberBox = new Box(42);
console.log(stringBox.getValue()); // Hello
console.log(numberBox.getValue()); // 42
stringBox.setValue("World");
console.log(stringBox.getValue()); // World
Union type
|를 사용해 두 개 이상의 타입을 선언하는 방식
Union과 Generic 모두 여러 타입을 다룰 수 있음.
Union type의 특징
- 선언한 공통된 메소드만 사용 가능
- 리턴값이 하나의 타입이 아닌 선언된 Union 타입으로 지정됨.
function printLength(value: string | number): void {
console.log(value.length); // 에러 length는 숫자에 없음
}
function getStringOrNumber(flag: boolean): string | number {
return flag ? "Hello" : 42;
}
const result: string | number = getStringOrNumber(true);
console.log(result) // Hello
Union
type StringOrNumber = string | number;
function printStringOrNumber(value: StringOrNumber): void {
console.log(value);
}
printStringOrNumber("Hello"); // Hello
printStringOrNumber(42); // 42
Generic
type Box<T> = {
value: T;
};
function printBoxValue<T>(box: Box<T>): void {
console.log(box.value);
}
const stringBox: Box<string> = { value: "World" };
const numberBox: Box<number> = { value: 123 };
printBoxValue(stringBox); // World
printBoxValue(numberBox); // 123
제약조건 (Constraints / keyof)
Constraints
Generic T에 제약 조건(extends)을 설정한다.
제약조건을 벗어나는 타입을 선언하면 에러가 발생한다.
const printMessage = <T extends string | number>(message: T): T => {
return message;
}
printMessage<String>("1");
printMessage<Number>(1);
printMessage<Boolean>(false); // 에러 : T extends의 제약조건에 불린이 없음
keyof
매개변수로 주어진 객체의 키의 타입으로 제한하는 타입 매개변수를 선언할 수 있음.
const getProperty = <T extends object, U extends keyof T>(obj: T, key: U) => {
return obj[key]
}
getProperty({ a : 1, b : 2, c : 3 }, "a");
getProperty({ a : 1, b : 2, c : 3 }, "z"); // 에러 : z는 객체의 프로퍼티 네임이 아님
디자인 패턴 (Factory Pattern with Generics)
· 객체를 생성하는 인터페이스만 미리 정의하고, 인스턴스를 만들 클래스의 결정은 서브 클래스가 내리는 패턴
· 여러 개의 서브 클래스를 가진 슈퍼 클래스가 있을 때, 입력에 따라 하나의 서브 클래스의 인스턴스를 반환한다.
'교육 > 엘리스 SW 트랙' 카테고리의 다른 글
[엘리스sw] 6주차 3일 - MiddleWare와 Restful API (0) | 2024.01.29 |
---|---|
[엘리스sw] 6주차 1일 - npm과 모듈, Express (0) | 2024.01.28 |
[엘리스sw] 5주차 3일 - 타입스크립트 개념, 클래스 (0) | 2024.01.25 |
[엘리스sw] 5주차 1일 - Node.js와 MongoDB I (0) | 2024.01.20 |
[엘리스sw] 4주차 3일 - async/await, API (0) | 2024.01.15 |