Woongjae Lee
NHN Dooray - Frontend Team
2woongjae@gmail.com
2woongjae@gmail.com
function helloString(message: string): string {
return message;
}
function helloNumber(message: number): number {
return message;
}
// 더 많은 반복된 함수들 ...
function hello(message: any): any {
return message;
}
function helloGeneric<T>(message: T): T {
return message;
}
console.log(hello('Mark').length);
console.log(hello(35).length);
console.log(helloGeneric(35).toString()); // console.log(helloGeneric<number>(35).toString());
// hello 의 리턴이 any 이기 때문에 타입 헬퍼가 제대로 되지 않음
// helloGeneric 을 사용하면 정상적으로 사용가능
function helloGeneric<T>(message: T): T {
return message;
}
function hello<T>(message: T): T {
return message;
}
console.log(hello<string>('Hello'));
let age = hello(35);
hello<number>('35');
/*
1. Generic 타입을 쓰지 않으면, T 로 추론
2. Generic 타입을 쓰면, T 를 확인
*/
function hello<T>(messages: T[]): T {
return messages[0];
}
console.log(hello<string>(['Hello', 'World']));
/*
hello 함수의 제네릭 타입을 [] 를 이용하여 배열로 사용할 수 있음
*/
type HelloGeneric = <T>(message: T) => T;
const hello: HelloGeneric = <T>(message: T): T => {
return message;
}
console.log(hello<string>('Hello').length);
/*
구현체에 return T 를 설정하지 않아도,
return false 시 오류가 나지 않는다?
*/
class Person<T> {
private _name: T;
private _age: number;
constructor(name: T) {
this._name = name;
}
}
new Person('Mark');
// new Person<string>(35);
/*
명시적으로 제네릭 타입을 설정하면 오류
*/
class Person<T extends string | number> {
private _name: T;
private _age: T;
constructor(name: T) {
this._name = name;
}
}
new Person('Mark');
new Person(35);
// new Person(true);
/*
T 가 string 또는 number 를 상속받기 때문에 boolean 은 안된다.
*/
class Person<T, K> {
private _name: T;
private _age: K;
constructor(name: T, age: K) {
this._name = name;
this._age = age;
}
}
new Person('Mark', 35);
interface Person {
name: string;
age: number;
}
const person: Person = {
name: 'Mark',
age: 35
};
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
function setProperty<T, K extends keyof T>(obj: T, key: K, value: T[K]): void {
obj[key] = value;
}
console.log(getProperty(person, 'name'));
// console.log(getProperty(person, fullname));
setProperty(person, 'name', 'Anna');
console.log(getProperty(person, 'name'));
// setProperty(person, 'name', 24);
const array = ['first', 'second'];
const obj = {
name: 'Mark',
age: 35
};
// 배열에 for..of 이용
for (const item of array) {
console.log(typeof item + ', ' + item);
}
// 배열에 for..in 이용
// item 이 string 타입의 숫자
for (const item in array) {
console.log(typeof item + ', ' + item);
}
// 객체에 for..of 이용 => 오류
/*
for (const item of obj) {
console.log(typeof item + ', ' + item);
}
*/
// 객체에 for..in 이용
for (const item in obj) {
console.log(typeof item + ', ' + item);
}
// 객체의 keys 들에 for..of 이용
for (const item of Object.keys(obj)) {
console.log(typeof item + ', ' + item);
}
const array = ['first', 'second'];
// ts
array.forEach((item) => {
console.log(item);
});
// js
array.forEach(function (item) {
console.log(item);
});
/*
target 이 es3 인데도 forEach 는 트랜스파일이 되지 않았음.
https://github.com/Microsoft/TypeScript/issues/2410
*/
interface IteratorResult<T> {
done: boolean;
value: T;
}
interface Iterator<T> {
next(value?: any): IteratorResult<T>;
return?(value?: any): IteratorResult<T>;
throw?(e?: any): IteratorResult<T>;
}
interface Iterable<T> {
[Symbol.iterator](): Iterator<T>;
}
interface IterableIterator<T> extends Iterator<T> {
[Symbol.iterator](): IterableIterator<T>;
}
class CustomIterable implements Iterable<string> {
private _array: Array<string> = ['first', 'second'];
[Symbol.iterator]() {
var nextIndex = 0;
return {
next: () => {
return {
value: this._array[nextIndex++],
done: nextIndex > this._array.length
}
}
}
}
}
const cIterable = new CustomIterable();
for (const item of cIterable) {
console.log(item);
}
experimentalDecorators 추가
step4. vscode 컴파일 설정
${workspaceRoot}/node_modules/.bin/tsc
command + shift + <B>
function hello(constructorFn: Function) {
console.log(constructorFn);
}
function helloFactory(show: boolean) {
if (show) {
return hello;
} else {
return null;
}
}
// @hello
@helloFactory(true)
class Person {
constructor() {
console.log('new Person()');
}
}
new Person();
/*
helloFactory 는 팩토리 스타일
*/
function addHello(constructorFn: Function) {
constructorFn.prototype.hello = function() {
console.log('hello');
}
}
@addHello
class Person {
constructor() {
console.log('new Person()');
}
}
const person = new Person();
(<any>person).hello();
function editable(canBeEdit: boolean) {
return function(target: any, propName: string, description: PropertyDescriptor) {
console.log(canBeEdit);
console.log(target);
console.log(propName);
console.log(description);
description.writable = canBeEdit;
}
}
class Person {
constructor() {
console.log('new Person()');
}
@editable(true)
hello() {
console.log('hello');
}
}
const person = new Person();
person.hello();
person.hello = function() {
console.log('world');
}
person.hello();
function writable(canBeWrite: boolean) {
return function(target: any, propName: string): any {
console.log(canBeWrite);
console.log(target);
console.log(propName);
return {
writable: canBeWrite
}
}
}
class Person {
@writable(false)
name: string = 'Mark';
constructor() {
console.log('new Person()');
}
}
const person = new Person();
console.log(person.name);
/*
undefined
*/
function printInfo(target: any, methodName: string, paramIndex: number) {
console.log(target);
console.log(methodName);
console.log(paramIndex);
}
class Person {
private _name: string;
private _age: number;
constructor(name: string, @printInfo age: number) {
this._name = name;
this._age = age;
}
hello(@printInfo message: string) {
console.log(message);
}
}
/*
Person { hello: [Function] }
hello
0
[Function: Person]
undefined
1
*/
const array1 = [];
const array2 = ['a', 'b', 'c'];
const array3 = ['a', 1, false];
class Animal {
name: string;
}
class Dog extends Animal {
dog: string;
}
class Cat extends Animal {
cat: string;
}
const array4 = [new Dog(), new Cat()];
function hello(message: string | number) {
if (message === 'world') {
return 'world';
} else {
return 0;
}
}
interface Person {
name: string;
age: number;
}
interface Car {
brand: string;
wheel: number;
}
function isPerson(arg: any): arg is Person {
return arg.name !== undefined;
}
function hello(arg: Person | Car) {
if (isPerson(arg)) {
console.log(arg.name);
// console.log(arg.brand);
} else {
// console.log(arg.name);
console.log(arg.brand);
}
}
By Woongjae Lee
타입스크립트 한국 유저 그룹 기초 스터디 201705