(원문) http://www.typescriptlang.org/Handbook
[Modules]
module 내부에서 정의된 methods들을 외부에서 사용하려면 export keyword를 사용해야 함.
module Validation { export interface StringValidator { isAcceptable(s: string): boolean; } var lettersRegexp = /^[A-Za-z]+$/; var numberRegexp = /^[0-9]+$/; export class LettersOnlyValidator implements StringValidator { isAcceptable(s: string) { return lettersRegexp.test(s); } } export class ZipCodeValidator implements StringValidator { isAcceptable(s: string) { return s.length === 5 && numberRegexp.test(s); } } } // Some samples to try var strings = ['Hello', '98052', '101']; // Validators to use var validators: { [s: string]: Validation.StringValidator; } = {}; validators['ZIP code'] = new Validation.ZipCodeValidator(); validators['Letters only'] = new Validation.LettersOnlyValidator(); // Show whether each string passed each validator strings.forEach(s => { for (var name in validators) { console.log('"' + s + '" ' + (validators[name].isAcceptable(s) ? ' matches ' : ' does not match ') + name); } });
[Multi-file internal modules]
독립된 파일을 export해서 사용하는 방법.
/// <reference path="xxxx.ts" /> 를 명시하여 다른 파일에 존재하지만 컴파일러에서는 한 파일로 구성된것으로 취급
Validation.ts
module Validation { export interface StringValidator { isAcceptable(s: string): boolean; } }
LettersOnlyValidator.ts
/// <reference path="Validation.ts" /> module Validation { var lettersRegexp = /^[A-Za-z]+$/; export class LettersOnlyValidator implements StringValidator { isAcceptable(s: string) { return lettersRegexp.test(s); } } }
ZipCodeValidator.ts
/// <reference path="Validation.ts" /> module Validation { var numberRegexp = /^[0-9]+$/; export class ZipCodeValidator implements StringValidator { isAcceptable(s: string) { return s.length === 5 && numberRegexp.test(s); } } }
Test.ts
/// <reference path="Validation.ts" /> /// <reference path="LettersOnlyValidator.ts" /> /// <reference path="ZipCodeValidator.ts" /> // Some samples to try var strings = ['Hello', '98052', '101']; // Validators to use var validators: { [s: string]: Validation.StringValidator; } = {}; validators['ZIP code'] = new Validation.ZipCodeValidator(); validators['Letters only'] = new Validation.LettersOnlyValidator(); // Show whether each string passed each validator strings.forEach(s => { for (var name in validators) { console.log('"' + s + '" ' + (validators[name].isAcceptable(s) ? ' matches ' : ' does not match ') + name); } });
컴파일할 때는 파일들을 컴파일 해서 하나의 JavaScript 파일(--out sample.js)로 만들거나
tsc --out sample.js Validation.ts LettersOnlyValidator.ts ZipCodeValidator.ts Test.ts각각의 파일들을 컴파일 해서 모든 JavaScript 결과물들을 명시하는 방법이 있다.
<script src="Validation.js" type="text/javascript" /> <script src="LettersOnlyValidator.js" type="text/javascript" /> <script src="ZipCodeValidator.js" type="text/javascript" /> <script src="Test.js" type="text/javascript" />
[Going External]
위의 reference tag를 사용하지 않고 아래 import를 사용하는 방법이 있음.
import someMod = require('someModule');
컴파일 시 import 구문을 확인하여 관련 파일들을 컴파일하게 된다.
다만 컴파일 시 --module flag를 지정하여 external module target을 알려줘야 한다. (자세한 개념은 모르겠으니 아래 링크를 참고
- JavaScript 표준을 위한 움직임: CommonJS와 AMD [http://helloworld.naver.com/helloworld/12864] )
tsc --module commonjs Test.ts
Validation.ts
export interface StringValidator { isAcceptable(s: string): boolean; }
LettersOnlyValidator.ts
import validation = require('./Validation'); var lettersRegexp = /^[A-Za-z]+$/; export class LettersOnlyValidator implements validation.StringValidator { isAcceptable(s: string) { return lettersRegexp.test(s); } }
ZipCodeValidator.ts
import validation = require('./Validation'); var numberRegexp = /^[0-9]+$/; export class ZipCodeValidator implements validation.StringValidator { isAcceptable(s: string) { return s.length === 5 && numberRegexp.test(s); } }
Test.ts
import validation = require('./Validation'); import zip = require('./ZipCodeValidator'); import letters = require('./LettersOnlyValidator'); // Some samples to try var strings = ['Hello', '98052', '101']; // Validators to use var validators: { [s: string]: validation.StringValidator; } = {}; validators['ZIP code'] = new zip.ZipCodeValidator(); validators['Letters only'] = new letters.LettersOnlyValidator(); // Show whether each string passed each validator strings.forEach(s => { for (var name in validators) { console.log('"' + s + '" ' + (validators[name].isAcceptable(s) ? ' matches ' : ' does not match ') + name); } });
** 흠.. 모르겠다.. 일단.. 생략..
[Functions]
일반적인 TypeScript에서의 function definition이다.
var myAdd: (x:number, y:number)=>number = function(x: number, y: number): number { return x+y; };
[Inferring the types]
첫번째에서는 function parameter의 type을 지정했지만 두번째 에서는 x, y의 type을 지정하지 않았지만 TypeScript compiler에서는 number로 유추하여 처리한다고 함.
// myAdd has the full function type var myAdd = function(x: number, y: number): number { return x+y; }; // The parameters 'x' and 'y' have the type number var myAdd: (baseValue:number, increment:number)=>number = function(x, y) { return x+y; };
[Optional and Default Parameters]
JavaScript와 다르게 TypeScript에서는 function의 parameter의 수가 맞아야 한다.
function buildName(firstName: string, lastName: string) { return firstName + " " + lastName; } var result1 = buildName("Bob"); //error, too few parameters var result2 = buildName("Bob", "Adams", "Sr."); //error, too many parameters var result3 = buildName("Bob", "Adams"); //ah, just right
Parameter를 optional로 처리하기 위해서는 다음과 같이 '?'를 붙여주면 됨.
function buildName(firstName: string, lastName?: string) { if (lastName) return firstName + " " + lastName; else return firstName; } var result1 = buildName("Bob"); //works correctly now var result2 = buildName("Bob", "Adams", "Sr."); //error, too many parameters var result3 = buildName("Bob", "Adams"); //ah, just right
아니면 default value를 지정해 주어 처리할 수 도 있음.
unction buildName(firstName: string, lastName = "Smith") { return firstName + " " + lastName; } var result1 = buildName("Bob"); //works correctly now, also var result2 = buildName("Bob", "Adams", "Sr."); //error, too many parameters var result3 = buildName("Bob", "Adams"); //ah, just right
[Rest Parameters]
reset parameter 명칭이 맞는지 모르겠지만 몇개의 parameter가 들어올 지 모르는 함수의 경우 C 같은 곳에서 '...'로 지정해 놓는 것과 같은 문법을 TypeScript에서 지원한다.
function buildName(firstName: string, ...restOfName: string[]) { return firstName + " " + restOfName.join(" "); } var employeeName = buildName("Joseph", "Samuel", "Lucas", "MacKinzie");
JavaScript에서는 아래와 같이 처리할 수 있음.
https://www.inkling.com/read/javascript-definitive-guide-david-flanagan-6th/chapter-8/function-arguments-and
function max(/* ... */) { var max = Number.NEGATIVE_INFINITY; // Loop through the arguments, looking for, and remembering, the biggest. for(var i = 0; i < arguments.length; i++) if (arguments[i] > max) max = arguments[i]; // Return the biggest return max; } var largest = max(1, 10, 100, 2, 3, 1000, 4, 5, 10000, 6); // => 10000[Lambdas and using 'this']
JavaScript에서 this 사용은 강력하고 유연한 객체 접근을 도와주지만 호출 시 올바른 객체에 접근할 수 있어야 하므로 cost가 발생된다.
아래의 예제에서 cardPicker()를 호출할 경우 deck.createCardPicker()내의 this는 deck를 가리키는게 아니라 Window 개체를 가리키게 되어 정상적으로 동작되지 않는다.
var deck = { suits: ["hearts", "spades", "clubs", "diamonds"], cards: Array(52), createCardPicker: function() { return function() { var pickedCard = Math.floor(Math.random() * 52); var pickedSuit = Math.floor(pickedCard / 13); return {suit: this.suits[pickedSuit], card: pickedCard % 13}; } } } var cardPicker = deck.createCardPicker(); var pickedCard = cardPicker(); alert("card: " + pickedCard.card + " of " + pickedCard.suit);
다른 방법으로 수정할 수 있으나 (아래 링크 참조) lambda 문법을 사용해서 생성되었을 때의 this를 capture할 수 있다.
Understanding JavaScript Function Invocation and “this”
: http://yehudakatz.com/2011/08/11/understanding-javascript-function-invocation-and-this/
JavaScript를 제대로 몰라서 위의 방법을 몰라 눈가리고 아웅식으로 전역처리해서 넘어갔었는데.. 부끄럽다..
var deck = { suits: ["hearts", "spades", "clubs", "diamonds"], cards: Array(52), createCardPicker: function() { // Notice: the line below is now a lambda, allowing us to capture 'this' earlier return () => { var pickedCard = Math.floor(Math.random() * 52); var pickedSuit = Math.floor(pickedCard / 13); return {suit: this.suits[pickedSuit], card: pickedCard % 13}; } } } var cardPicker = deck.createCardPicker(); var pickedCard = cardPicker(); alert("card: " + pickedCard.card + " of " + pickedCard.suit);
[Overloads]
... 나중에..
[Generics]
Generic을 사용하는 이유 중 하나는 데이터형에 상관없이 유연한 재사용 가능한 코드를 만드는 것이겠고 그것을 Type script에서는 지원한다.
기본적으로 아래 코드르
function identity(arg: number): number { return arg; }모든 type을 받고 제공할 수 있도록 고칠 수 있고
function identity(arg: any): any { return arg; }좀 더 나아가서 함수에서 사용하는 data type을 아래와 같이 선언해 줄 수 있음.
function identity<T>(arg: T): T { return arg; }위 Generic 함수를 사용하는 방법은 아래와 같이 explicit, implicit 하게 쓸 수 있음.
var output = identity<string>("myString"); // type of output will be 'string'
var output = identity("myString"); // type of output will be 'string'코드의 간결함을 위해 implicit하게 사용할 수 있으며 이때 compiler는 argument type을 기반하여 generic type을 유추한다.
[Working with Generic Type Variables]
T type의 array을 argument로 사용하려면 두번째 예제 처럼 해당 type을 T의 array type으로 특수화 해야 함.
function loggingIdentity<T>(arg: T): T { console.log(arg.length); // Error: T doesn't have .length return arg; }
function loggingIdentity<T>(arg: T[]): T[] { console.log(arg.length); // Array has a .length, so no more error return arg; }
[Generic Types]
기존 function prototype ( argument : type ) => return 앞에 generic type <T>만 붙여
Generic typed function을 type의 varaialbe을 선언하는 방법과
function identity<T>(arg: T): T { return arg; } var myIdentity: <T>(arg: T)=>T = identity;object literal type으로 지정해서 사용할 수 있음.
function identity<T>(arg: T): T { return arg; } var myIdentity: {<T>(arg: T): T} = identity;interface를 지정해서 사용하는 방법도 있다.
하지만 interface의 generic type이 명시적으로 선언되어 있지 않아 모호한 상황이 발생할 수도 있겠다.
interface GenericIdentityFn { <T>(arg: T): T; } function identity<T>(arg: T): T { return arg; } var myIdentity: GenericIdentityFn = identity;interface도 generic type으로 선언해서 interface 사용 시 명시적으로 generic type을 지정하도록 하는게 바람직 할 듯.
interface GenericIdentityFn<T> { (arg: T): T; } function identity<T>(arg: T): T { return arg; } var myIdentity: GenericIdentityFn<number> = identity;
[Generic Classes]
문법은 일반적이다.
class GenericNumber<T> { zeroValue: T; add: (x: T, y: T) => T; } var myGenericNumber = new GenericNumber<number>(); myGenericNumber.zeroValue = 0; myGenericNumber.add = function(x, y) { return x + y; };
var stringNumeric = new GenericNumber<string>(); stringNumeric.zeroValue = ""; stringNumeric.add = function(x, y) { return x + y; }; alert(stringNumeric.add(stringNumeric.zeroValue, "test"));어떤 class type parameter를 선언해서 GenericNumber class를 사용해도 상관이 없으나 static member에는 class type parameter를 사용하지 못한다.
[Generic Constraints]
Generic type의 member method를 제한하고 싶을 경우 interface를 사용하여 제어할 수 있음.
interface Lengthwise { length: number; } function loggingIdentity<T extends Lengthwise>(arg: T): T { console.log(arg.length); // Now we know it has a .length property, so no more error return arg; }아래와같이 interface를 맞춰 주면 ok
loggingIdentity({length: 10, value: 3});
[Using Type parameters in Generic Constraints]
.. 나중에
function find<T, U extends Findable<T>>(n: T, s: U) { // errors because type parameter used in constraint // ... } find (giraffe, myAnimals);
function find<T>(n: T, s: Findable<T>) { // errors because type parameter used in constraint // ... } find(giraffe, myAnimals);
[Using Class Types in Generics]
.. 나중에
function create<T>(c: {new(): T; }): T { return new c(); }
class BeeKeeper { hasMask: boolean; } class ZooKeeper { nametag: string; } class Animal { numLegs: number; } class Bee extends Animal { keeper: BeeKeeper; } class Lion extends Animal { keeper: ZooKeeper; } function findKeeper<A extends Animal, K> (a: {new(): A; prototype: {keeper: K}}): K { return null; } findKeeper(Lion).nametag; // works!
댓글 없음:
댓글 쓰기