문서의 선택한 두 판 사이의 차이를 보여줍니다.
| 양쪽 이전 판이전 판다음 판 | 이전 판 | ||
| typescript:interface [2018/08/03 22:45] – [Basic Example] taekgu | typescript:interface [2025/04/15 10:05] (현재) – 바깥 편집 127.0.0.1 | ||
|---|---|---|---|
| 줄 58: | 줄 58: | ||
| 아래의 코드에서 문법 오류가 일어날까요? | 아래의 코드에서 문법 오류가 일어날까요? | ||
| + | <code javascript> | ||
| interface IBook { | interface IBook { | ||
| bookName: string; | bookName: string; | ||
| 줄 74: | 줄 74: | ||
| }; | }; | ||
| - | printBookInfo(myBook); | + | printBookInfo(myBook); |
| 원래 예상대로라면 이 코드는 문제가 있는 것이 맞습니다. myBook이라는 객체는 IBook interface type으로 지정되지 않고 parameter로 전달이 되었거든요. 하지만 이 코드는 에러없이 컴파일이 진행됩니다. | 원래 예상대로라면 이 코드는 문제가 있는 것이 맞습니다. myBook이라는 객체는 IBook interface type으로 지정되지 않고 parameter로 전달이 되었거든요. 하지만 이 코드는 에러없이 컴파일이 진행됩니다. | ||
| 줄 87: | 줄 87: | ||
| 해서 저 위의 코드는 에러없이 사용할 수 있습니다. | 해서 저 위의 코드는 에러없이 사용할 수 있습니다. | ||
| - | Optional Properties | + | ==== Optional Properties |
| TypeScript interface의 모든 property와 method는 구현하는 클래스 혹은 구현 객체에서 기본적으로 모두 재정의되어야 합니다. 하지만 Optional Property( property 중 ? 가 붙어있는 property를 의미합니다. )를 이용하면 해당 property는 재정의하지 않아도 상관없습니다. 즉, 선택적으로 구현여부를 결정할 수 있는 property가 optional property입니다. | TypeScript interface의 모든 property와 method는 구현하는 클래스 혹은 구현 객체에서 기본적으로 모두 재정의되어야 합니다. 하지만 Optional Property( property 중 ? 가 붙어있는 property를 의미합니다. )를 이용하면 해당 property는 재정의하지 않아도 상관없습니다. 즉, 선택적으로 구현여부를 결정할 수 있는 property가 optional property입니다. | ||
| 아래의 예를 가지고 살펴보겠습니다. | 아래의 예를 가지고 살펴보겠습니다. | ||
| + | <code javascript> | ||
| interface IBook { | interface IBook { | ||
| bookName: string; | bookName: string; | ||
| 줄 116: | 줄 116: | ||
| printBookInfo(myBook); | printBookInfo(myBook); | ||
| - | Readonly Properties | + | </ |
| + | ==== Readonly Properties | ||
| readonly keyword를 이용해 객체가 처음 생성되는 시점에만 property들을 수정가능하도록 설정할 수 있습니다. | readonly keyword를 이용해 객체가 처음 생성되는 시점에만 property들을 수정가능하도록 설정할 수 있습니다. | ||
| 한번 값이 세팅되면 그 후에는 수정할 수 없게됩니다. | 한번 값이 세팅되면 그 후에는 수정할 수 없게됩니다. | ||
| + | <code javascript> | ||
| interface Point { | interface Point { | ||
| readonly x: number; | readonly x: number; | ||
| 줄 127: | 줄 128: | ||
| let p1: Point = { x: 10, y: 20 }; | let p1: Point = { x: 10, y: 20 }; | ||
| - | p1.x = 100; // 오류 발생 | + | p1.x = 100; // 오류 발생</ |
| TypeScript는 또 ReadonlyArray< | TypeScript는 또 ReadonlyArray< | ||
| + | <code javascript> | ||
| let arr: number[] = [1, 2, 3, 4]; | let arr: number[] = [1, 2, 3, 4]; | ||
| 줄 138: | 줄 139: | ||
| arr = roArray; | arr = roArray; | ||
| - | arr = roArray as number[]; // 가능 | + | arr = roArray as number[]; // 가능</ |
| 위의 코드도 쉽게 이해할 수 있습니다. 마지막 코드 정도만 주의하면 될 듯 합니다. | 위의 코드도 쉽게 이해할 수 있습니다. 마지막 코드 정도만 주의하면 될 듯 합니다. | ||
| 이렇게 readonly property는 const와 비슷한 역할을 하게됩니다. 단 const는 변수의 선언에 사용되며 readonly는 property 지정에 사용된다는 점만 기억하시면 됩니다. | 이렇게 readonly property는 const와 비슷한 역할을 하게됩니다. 단 const는 변수의 선언에 사용되며 readonly는 property 지정에 사용된다는 점만 기억하시면 됩니다. | ||
| - | Function Types | + | ==== Function Types ==== |
| interface는 function의 type을 지정하는데 사용할 수 있습니다. 이 경우 parameter의 리스트와 리턴타입만을 가지고 있는 함수의 선언과 비슷한 형태를 가지게 됩니다. 아래의 예를 보죠. | interface는 function의 type을 지정하는데 사용할 수 있습니다. 이 경우 parameter의 리스트와 리턴타입만을 가지고 있는 함수의 선언과 비슷한 형태를 가지게 됩니다. 아래의 예를 보죠. | ||
| + | <code javascript> | ||
| interface myInterface { | interface myInterface { | ||
| (myName: string, myAge: number): void; | (myName: string, myAge: number): void; | ||
| 줄 156: | 줄 157: | ||
| myFunc(" | myFunc(" | ||
| - | Indexable Types | + | </ |
| + | ==== Indexable Types ==== | ||
| JavaScript의 객체를 사용하기 위해서는 일반적으로 " | JavaScript의 객체를 사용하기 위해서는 일반적으로 " | ||
| 아래의 코드는 JavaScript 코드입니다. | 아래의 코드는 JavaScript 코드입니다. | ||
| + | <code javascript> | ||
| let obj = { | let obj = { | ||
| myName: ' | myName: ' | ||
| 줄 173: | 줄 175: | ||
| for(let i = 0; i< keys.length; | for(let i = 0; i< keys.length; | ||
| console.log(obj[keys[i]]); | console.log(obj[keys[i]]); | ||
| - | } | + | }</ |
| 위의 코드는 문법에러가 발생하지 않고 결과도 잘 출력이 됩니다. obj 객체에 접근할 때 [ ] 형태를 이용해서 key값에 접근해서 value값을 출력하는 간단한 예제입니다. | 위의 코드는 문법에러가 발생하지 않고 결과도 잘 출력이 됩니다. obj 객체에 접근할 때 [ ] 형태를 이용해서 key값에 접근해서 value값을 출력하는 간단한 예제입니다. | ||
| 하지만 이 코드를 TypeScript로 작성하면 코드에러가 발생합니다. 해당 파일에 대한 확장자만 .js에서 .ts로 변경해보면 obj[keys[i]에서 다음과 같은 에러가 발생하는 것을 볼 수 있습니다. | 하지만 이 코드를 TypeScript로 작성하면 코드에러가 발생합니다. 해당 파일에 대한 확장자만 .js에서 .ts로 변경해보면 obj[keys[i]에서 다음과 같은 에러가 발생하는 것을 볼 수 있습니다. | ||
| + | <code javascript> | ||
| Element implicitly has an ' | Element implicitly has an ' | ||
| - | '{ myName: string; myAddress: string; }' has no index signature. | + | '{ myName: string; myAddress: string; }' has no index signature.</ |
| 쉽게 말하면 index signature를 이용하지 않았기 때문에 property에 접근할 때 어떤 타입인지를 확인할 수 없어서 묵시적으로 any 타입을 이용하게 된다는 의미입니다. 하지만 우리는 TypeScript compiler 옵션 중 noImplicitAny 속성을 true로 해 놓았기 때문에 문제가 발생하는 것입니다. (noImplicitAny: | 쉽게 말하면 index signature를 이용하지 않았기 때문에 property에 접근할 때 어떤 타입인지를 확인할 수 없어서 묵시적으로 any 타입을 이용하게 된다는 의미입니다. 하지만 우리는 TypeScript compiler 옵션 중 noImplicitAny 속성을 true로 해 놓았기 때문에 문제가 발생하는 것입니다. (noImplicitAny: | ||
| 줄 187: | 줄 189: | ||
| 좀 더 좋은 해결책은 interface로 index signature를 설정해서 사용하는 것입니다. 이걸 Indexable Type이라고 합니다. 아래의 코드처럼 interface를 이용해 index signature를 설정합니다. | 좀 더 좋은 해결책은 interface로 index signature를 설정해서 사용하는 것입니다. 이걸 Indexable Type이라고 합니다. 아래의 코드처럼 interface를 이용해 index signature를 설정합니다. | ||
| + | <code javascript> | ||
| interface IObj { | interface IObj { | ||
| [idx: string]: string; | [idx: string]: string; | ||
| 줄 203: | 줄 205: | ||
| for(let i = 0; i< keys.length; | for(let i = 0; i< keys.length; | ||
| console.log(obj[keys[i]]); | console.log(obj[keys[i]]); | ||
| - | } | + | }</ |
| 추가적으로 union type을 이용한 다음의 코드도 살펴보시면 됩니다. | 추가적으로 union type을 이용한 다음의 코드도 살펴보시면 됩니다. | ||
| + | <code javascript> | ||
| interface IObj { | interface IObj { | ||
| [idx: string]: string | number; | [idx: string]: string | number; | ||
| 줄 226: | 줄 228: | ||
| for(let i = 0; i< keys.length; | for(let i = 0; i< keys.length; | ||
| console.log(obj[keys[i]]); | console.log(obj[keys[i]]); | ||
| - | } | + | }</ |
| 마지막으로 앞에서 나온 readonly property를 이용하면 ReadonlyArray처럼 사용할 수 있습니다. | 마지막으로 앞에서 나온 readonly property를 이용하면 ReadonlyArray처럼 사용할 수 있습니다. | ||
| + | <code javascript> | ||
| interface ReadonlyStringArray { | interface ReadonlyStringArray { | ||
| readonly [index: number]: string; | readonly [index: number]: string; | ||
| } | } | ||
| let myArr: ReadonlyStringArray = [" | let myArr: ReadonlyStringArray = [" | ||
| - | myArr[2] = " | + | myArr[2] = " |
| - | Class Types | + | ==== Class Types ==== |
| interface의 가장 일반적인 사용법은 Java나 C# | interface의 가장 일반적인 사용법은 Java나 C# | ||
| + | <code javascript> | ||
| interface IPerson { | interface IPerson { | ||
| [idx: string]: string | number | Function; | [idx: string]: string | number | Function; | ||
| 줄 265: | 줄 267: | ||
| const obj = new Person(" | const obj = new Person(" | ||
| - | obj.printInfo(obj); | + | obj.printInfo(obj); |
| 위와 같은 일반적인 경우가 사실은 대부분입니다. ^^; 여기에 추가적인 몇가지만 살펴보겠습니다. 이전 강좌에서 일급함수(first class function)개념에 대해서 언급했었는데 기억하시나요? | 위와 같은 일반적인 경우가 사실은 대부분입니다. ^^; 여기에 추가적인 몇가지만 살펴보겠습니다. 이전 강좌에서 일급함수(first class function)개념에 대해서 언급했었는데 기억하시나요? | ||
| 그래서 다음의 JavaScript코드는 정상적으로 동작합니다. | 그래서 다음의 JavaScript코드는 정상적으로 동작합니다. | ||
| + | <code javascript> | ||
| const PersonFactory = { | const PersonFactory = { | ||
| getInstance: | getInstance: | ||
| 줄 290: | 줄 292: | ||
| let obj = PersonFactory.getInstance(Person, | let obj = PersonFactory.getInstance(Person, | ||
| - | obj.printInfo(); | + | obj.printInfo(); |
| 위의 코드에서 Person 생성자를 PersonFactory.getInstance 함수의 인자로 넘겨서 사용했습니다. JavaScript에서는 문제없이 잘 동작합니다. 하지만 이 코드를 그대로 TypeScript에서 작성하면 코드에러가 발생합니다. | 위의 코드에서 Person 생성자를 PersonFactory.getInstance 함수의 인자로 넘겨서 사용했습니다. JavaScript에서는 문제없이 잘 동작합니다. 하지만 이 코드를 그대로 TypeScript에서 작성하면 코드에러가 발생합니다. | ||
| 일단 타입지정부터 엉망이니 좀 수정해서 보면 TypeScript코드는 다음과 같게 됩니다. | 일단 타입지정부터 엉망이니 좀 수정해서 보면 TypeScript코드는 다음과 같게 됩니다. | ||
| + | <code javascript> | ||
| const PersonFactory = { | const PersonFactory = { | ||
| getInstance: | getInstance: | ||
| 줄 316: | 줄 318: | ||
| let obj = PersonFactory.getInstance(Person, | let obj = PersonFactory.getInstance(Person, | ||
| - | obj.printInfo(); | + | obj.printInfo(); |
| 데이터 타입을 적절하게 지정해서 일단 코드 오류는 제거했습니다. 그런데 문제가 하나 있습니다. | 데이터 타입을 적절하게 지정해서 일단 코드 오류는 제거했습니다. 그런데 문제가 하나 있습니다. | ||
| + | <code javascript> | ||
| const PersonFactory = { | const PersonFactory = { | ||
| getInstance: | getInstance: | ||
| return new construct(name, | return new construct(name, | ||
| } | } | ||
| - | }; | + | };</ |
| 위의 코드에서 생성자를 인자로 받아올 때 타입을 어떻게 지정해야 할지 몰라 일단 모든 타입에 대응되는 any로 설정했습니다. any로 설정하면 문제없지만 우리는 any를 사용하지 않습니다. 좀 심하게 표현하자면 any를 사용할꺼면 굳이 TypeScript를 할 필요가 없습니다. 여하간 이 any를 없애고 정확한 타입을 명시하려 합니다. 그런데 어떤 타입을 써야하나요? | 위의 코드에서 생성자를 인자로 받아올 때 타입을 어떻게 지정해야 할지 몰라 일단 모든 타입에 대응되는 any로 설정했습니다. any로 설정하면 문제없지만 우리는 any를 사용하지 않습니다. 좀 심하게 표현하자면 any를 사용할꺼면 굳이 TypeScript를 할 필요가 없습니다. 여하간 이 any를 없애고 정확한 타입을 명시하려 합니다. 그런데 어떤 타입을 써야하나요? | ||
| - | + | <code javascript> | |
| - | Cannot use ' | + | Cannot use ' |
| construct signature 없이 new를 사용할 수 없답니다. 그럼 이 construct signature를 어떻게 만들어야 할까요? 저 위에서는 index signature라는 걸 interface를 이용해서 선언하고 사용했습니다. 기억하시죠? | construct signature 없이 new를 사용할 수 없답니다. 그럼 이 construct signature를 어떻게 만들어야 할까요? 저 위에서는 index signature라는 걸 interface를 이용해서 선언하고 사용했습니다. 기억하시죠? | ||
| + | <code javascript> | ||
| interface IPersonConstructor { | interface IPersonConstructor { | ||
| new (n:string, a:number): Person; | new (n:string, a:number): Person; | ||
| 줄 357: | 줄 359: | ||
| let obj = PersonFactory.getInstance(Person, | let obj = PersonFactory.getInstance(Person, | ||
| - | obj.printInfo(); | + | obj.printInfo(); |
| 이렇게 사용하는 interface를 constructor interface 라고 표현하기도 합니다. 중요한 것은 interface로 constructor의 타입을 지정해 줄 수 있다는 것이고 construct signature라는 표현으로 interface내에 정의해서 사용합니다. | 이렇게 사용하는 interface를 constructor interface 라고 표현하기도 합니다. 중요한 것은 interface로 constructor의 타입을 지정해 줄 수 있다는 것이고 construct signature라는 표현으로 interface내에 정의해서 사용합니다. | ||
| - | interface의 확장 | + | ==== interface의 확장 |
| 하나의 interface는 다른 interface로 부터 상속받아서 확장될 수 있습니다. Java와 유사합니다. 다음의 코드로 이해하시면 됩니다. | 하나의 interface는 다른 interface로 부터 상속받아서 확장될 수 있습니다. Java와 유사합니다. 다음의 코드로 이해하시면 됩니다. | ||
| + | <code javascript> | ||
| interface Shape { | interface Shape { | ||
| color: string; | color: string; | ||
| 줄 374: | 줄 376: | ||
| let square = < | let square = < | ||
| square.color = " | square.color = " | ||
| - | square.sideLength = 10; | + | square.sideLength = 10;</ |
| let square = < | let square = < | ||
| + | <code javascript> | ||
| interface Shape { | interface Shape { | ||
| color: string; | color: string; | ||
| 줄 392: | 줄 394: | ||
| square.color = " | square.color = " | ||
| square.sideLength = 10; | square.sideLength = 10; | ||
| - | square.penWidth = 5.0; | + | square.penWidth = 5.0;</ |
| interface는 type check를 위해 사용되기 때문에 interface로는 객체를 생성할 수 없습니다. | interface는 type check를 위해 사용되기 때문에 interface로는 객체를 생성할 수 없습니다. | ||
| 일단 이 정도만 알아두어도 될 듯 보입니다. 내용이 생각보다 많은데 생각보다 많이 어렵지는 않습니다. 단지 헷갈릴 뿐이죠 ^^ 여러번 정독하면서 쓰임새를 알아두고 실제 코드에서 활용하면서 익히셔야 합니다. | 일단 이 정도만 알아두어도 될 듯 보입니다. 내용이 생각보다 많은데 생각보다 많이 어렵지는 않습니다. 단지 헷갈릴 뿐이죠 ^^ 여러번 정독하면서 쓰임새를 알아두고 실제 코드에서 활용하면서 익히셔야 합니다. | ||