23.10.13 (interface, generic)
인터페이스에 대한 설명 중 올바른 것 > 직접 인스턴스 생성 불가능, 변수 함수나 클래스 타입 체크 위해 사용
제네릭에 대한 설명 중 틀린 것 > 컴파일 시에는 타입 오류 발생 하지 않음
인터페이스
일반적으로 변수, 함수, 클래스에 타입 체크를 위해 사용됨
직접 인스턴스 생성 불가, 모든 메소드가 추상 메소드
추상 클래스의 추상 메소드와 달리 abstract키워드 사용 불가
es6지원 안함, 타입스크립트 인터페이스 지원
사용하는 이유
타입의 이름을 짓고 코드 안의 계약 정의함
프로젝트 외부에서 사용하는 코드의 계약 정의 하는 강한 방법
>객체의 스펙(속성과 속성 타입), 함수 파라미터, 함수 스펙(파라미터, 반환타입), 배열과 객체 접근 방식, 클래스
function sayName(obj : {name:string}) { console.log(obj.ame); }
let person = {name : "june" };
sayName(person);
>>
interface Person { name : string }
function sayName (obj: Person) { console.log(obj.name); }
ler person = {name: "june"); }
sayName(person);
>>인터페이스를 추가해 함수 매개변수 프로퍼티 정의 가능
정의한 프로퍼티 값을 누락하거나 정의하지 않은 값을 인수로 전달 시 컴파일 에러 발생
인터페이스 사용 예제
프로퍼티
컴파일러는 프로퍼티의 두 가지 요소를 검사함 > 필수요소 프로퍼티의 유무, 프로퍼티 타입
예약어로 프로퍼티 컨트롤 가능 > ?(optional properties), readonly
optional
프로퍼티 선언 시 이름 끝에 ?를 붙여 표시함
인터펭스에 속하지 않는 프로퍼티의 사용 방지, 사용 가능한 프로퍼티 기술 시 사용
객체 안 몇개의 프로퍼티만 채워 함수에 전달하는 "option bags"같은 패턴에 유용함
ex) interface MM{ color?:string width?: number }
readonly
객체가 처음 생성될 때만 값 설정 가능, 이후 수정 불가능
프로퍼티 앞 readonly붙여 사용
ex) interface Point { readonly x : number readonly y : number }
옵셔널, 읽기 전용 예제
readonly vs const
공통점 - 생성 후 배열 미변경 보장 > 수정 불가
차이점 - 변수는 const사용, 프로퍼티는 readonly사용
인터페이스 타입
타입에서 인터페이스는 함수, 클래스에서 사용 가능
함수 - js객체가 가질 수 있는 넓은 범위의 형태 기술, 프로퍼티 객체 기술 외 인터페이스는 함수 타입 설명
클래스 - 특정 통신 프로토콜을 충족하도록 명시적으로 강제함, 다른 언어에서 일반적으로 사용하는 방법과 동일
function type
함수의 인자 타입과 반환 값의 타입 정의 + 함수 타입 정의 시 사용
ex) interface searchFunc { (source:string, substring:string) : boolean }
let mysearch = searchFunc
mysearch = function (src, sub) {
let result = src.search(sub); return result > -1; }
mysearch = function (src,sub) { let result = src.search(sub); return "string"; }
class type
클래스가 특정 계약(contract)을 충족하도록 명시적으로 강제함
ex) interface animal { makeSound():void }
class dog implements animal { mmakeSound(): void { console.log("멍멍"); } }
interface확장
ex) interface animal { makeSound(): void }
interface dog extends animal { speed:number } //확장
class bulldog implements dog { makeSound(): void { console.log("멍멍"); } }
하이브리드 타입
js의 유연하고 동적인 타입 특성에 따라 인터페이스 또한 여러 타입을 조합 가능
함수 타입이면서 객체 타입 정의할 수 있는 인터페이스 구현 가능
ex) interface Counter { (start:number) : string
interval:number reset():void }
function getCounter():counter { let counter = function(start:number0 {} as Counter
counter.interval = 123; counter.reset = function() {} return counter; }
let c = getCounter(); c(10); c.reset(); c.interval = 5.0;
디자인 패턴(strategy pettern)
객체가 할 수 있는 행위들을 전략(strategy)으로 만들어 두고
동적으로 행위의 수정이 필요한 경우 전략을 바꾸는 것만으로 수정 가능하도록 만든 패턴
전략패턴 예시
generic
정적 type언어는 클래스나 함수 정의 시 타입선언을 해야 하는데 제네릭은 코드 작성 시가 아닌 코드 수행시 타입 명시함
코드 작성 시 식별자를 써 아직 정해지지 않은 타입 표시 > T,U,V 등 필드 이름의 첫글자를 사용하기도 함
사용하는 이유
재사용성이 높은 함수와 클래스 생성 가능
여러타입에서 동작 가능 > 한 번의 선언으로 다양한 타입에 재사용 가능 + 코드 가독성 향상)
오류 쉽게 포착
any타입 사용 시 컴파일때 타입 체크 안함 > 관련 메소드 힌트 사용 불가 > 컴파일 시 컴파일러가 오류 찾지 못함
타입을 미리 체크해 오류 찾을 수 있음
함수만들기
function sort<T>(items: T[]): T[]{ return items.sort(); }
const nums: number[] = [1,2,3,4];
const chars:string[] = ["a","b","c","d"];
sort<number>(nums);
sort<string>(chars);
클래스 만들기
class queue<T> {
protected data: Array<T> = [];
push(itme:T) { this.data.push(item); }
pop():T | undefined{ return this.dta.shift(); } }
const numberQueue = new Queue<number>();
numberQueue.push(0);
numberQueue.push("1"); //의도하지 않은 실수 사전 검출 가능
numberQueue.push(+"1"); //실수 사전 인지 및 수정 가능
유니온 타입
|을 사용해 두 개 이상의 타입을 선언하는 방식
선언한 공통된 메소드만 사용 가능, 리턴값이 하나의 타입이 아닌 선언된 유니온 타입으로 지정됨
ex) Union
const printMessage = (message:string | number ) => { return message; }
const message1 = printMessage(1234);
const message2 = printMessage("hello world");
유니온 타입 예제
generic
const printMessage2 = <T>(message:T) => { return message; }
const message1 = printMessage2<String>("hello world");
message1.length;
함수에 generic사용 예제
제약조건
원하지 않는 속성에 접근하는 것을 막기우해 사용
constraints - 특정 타입들로만 동작하는 제네릭 함수를 만들때 사용
key of - 두 객체를 비교할 때 사용
타입 매개변수 속성 키 값으로만 제한된 타입 매개변수 선언 위해 사용
constraints
제네릭 t에 제약조건 설정 (문자열 | 숫자) 제약조건 벗어나는 타입 선언 시 에러 발생
ex)
const printMessage = <T extends string | number> (message:T) : T => { return message; }
printMessage<string>("1");
printMessage<number>(1);
printMessage<boolean>(false); //error
key of
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"); //error
>>제네릭에서 T는 키 값이 a,b,c만 존재하기 때문에 U값에 z를 쓰면 오류가 발생함
디자인패턴(factoryo pattern with generics)
객체를 생성하는 인터페이스만 미리 정의하고 인스턴스를 만들 클래스의 결정은 서브 클래스가 내림
여러개의 서브 클래스를 가진 슈퍼 클래스 존재 시 입력에 따라 하나의 서브 클래스의 인스턴스 반환함
ex)interface Car{ drive(): void park():void }
class Bus implements Car { drive(): void{} park():void{} }
class Taxi implements Car { drive():void {} park(): void{} }
class CarFactory { static getInstance(type:string):Car {
switch(type) {
case "bus" : return new Bus();
default : return new Taxi(); } } }
const bus = CarFactory.getInstance("bus");
const taxi = CarFactory.getInstance("taxi");
export class CarFactory { static getInstance<T extends Car> (type: { new (): T}):T {
return new type(); } }
const bus = CarFactory.getInstance(Bus);
const taxi = CarFactory.getInstance(Taxi);