-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathgeneric.html
More file actions
198 lines (173 loc) · 4.84 KB
/
generic.html
File metadata and controls
198 lines (173 loc) · 4.84 KB
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>노재원의 블로그</title>
</head>
<body>
<h1>제네릭</h1>
<h2>Before</h2>
<pre>
// echo 함수를 만들어 본다.
function echo(param: number): number {
return param;
}
function echo1(param: any): any { // 여러 타입을 받을 수 있지만 엔진 입장에서 명확한 추론이 되지는 않는 모양.
return param;
}
function echo2<T>(param: T): T { // echo2함수에 T라는 타입의 제네릭을 추가함으로 인해 명확하게 타입 추론이 가능케 한다.
return param;
}
// function echo3<T>(param: T): T {
// console.info(param.length); // 어디에도 type T가 length를 가졌다는 단서가 없다. 모든 타입에서 사용할 수 있는 멤버 변수나 함수가 아니라면 섣불리 사용할 수 없다.
// return param;
// }
function echo3<T>(param: T[]): T[] {
// function echo3<T>(param: Array<T>): Array<T> { // 동일한 의미
console.info(param.length); // type T를 item으로 가지는 배열이 매개변수로 들어오고 있다. length를 가졌다는 추론이 가능해진다.
return param;
}
// type echo = <T>(param: T) => T;
type echo = <YD>(param: YD) => YD; // 같은 형식에 대해서 T이외의 다른 이름을 사용하여도 문제 없다. 다만 T는 type을 의미하는 약속인듯
// type echo = { <T>(param: T): T }; // function type을 object lieteral의 형태로도 작성 가능하다. function type을 interface로 작성하는 것과 이어진다.
const copyEcho2: echo = echo2;
interface echo1 {
<T>(param: T[]): T[]
}
interface echo2<T> { // echo1 과 같은 코드, 인터페이스의 모든 멤버가 <T>를 참조 할 수 있게 된다.
(param: T[]): T[]
}
const copyEcho3: echo1 = echo3;
const copyEcho4: echo2<number> = echo3;
class echoClass<T> {
memberVar: T;
constructor(init: T) {
this.memberVar = init;
}
test(param: T): T {
return param;
}
}
const echoClassInstance = new echoClass<string>('yd');
// 클래스에 타입을 지정 하더라도 static멤버는 해당 타입을 사용할 수 없다.
interface Lengthwise {
length: number;
}
function echo4<T extends Lengthwise>(param: T): T {
console.info(param.length);
return param;
}
function echo5<T, K extends keyof T>(obj: T, key: K) {
return obj[key];
}
type Constructor<T> = new () => T ; // { new (): T }는 잘 되는데 interface로 하면 뭔가 잘 안됨....
function factory<T>(c: Constructor<T>): T {
return new c();
}
class a {}
class b {}
class c {}
abstract class AA {
member: string;
protected constructor() {
this.member = 'YD';
}
abstract getMember(): string
}
function factory1<T extends AA>(c: new () => T): T {
return new c();
}
class d extends AA {
constructor() {
super();
}
getMember(): string {
return this.member;
}
}
class e {}
{
generic: true,
test: echo(1),
test1: echo1('jw'),
test2: echo2<boolean>(true), // echo2의 T를 boolean으로 명시 해준다.
// test2: echo2(true), // 이렇게 생략도 가능하다.
test3: echo3<number>([1,2,3,4,5,6]),
test4: copyEcho2<string>('yd'),
test5: copyEcho3<string>(['jw', 'yd']),
test6: copyEcho4([1,2,3]), // copyEcho4<number>([1,2,3]) 이렇게는 오류가 난다. 이미 제네릭 인터페이스에 타입을 지정했기 때문
test7: `${echoClassInstance.memberVar} and ${echoClassInstance.test('JW')}`,
test8: echo4<string>('YD'), // length 속성을 가진 type 사용이 가능하다.
test9: echo5({a: 1, b:2, c: 3}, 'c'), // echo5({a: 1, b:2, c: 3}, 'd') d가 object의 key가 아니기 때문에 에러
test10: factory(a),
test11: factory(b),
test12: factory(c),
test13: factory1(d),
// test14: factory1(e), // 타입에 맞지 않는 (이 경우엔 추상 클래스 AA를 구현한 클래스가 아닌 경우) 클래스인 경우 에러.
}
</pre>
<h2>After</h2>
<pre>
function echo(param) {
return param;
}
function echo1(param) {
return param;
}
function echo2(param) {
return param;
}
function echo3(param) {
console.info(param.length);
return param;
}
const copyEcho2 = echo2;
const copyEcho3 = echo3;
const copyEcho4 = echo3;
class echoClass {
constructor(init) {
this.memberVar = init;
}
test(param) {
return param;
}
}
const echoClassInstance = new echoClass('yd');
function echo4(param) {
console.info(param.length);
return param;
}
function echo5(obj, key) {
return obj[key];
}
function factory(c) {
return new c();
}
class a {
}
class b {
}
class c {
}
class AA {
constructor() {
this.member = 'YD';
}
}
function factory1(c) {
return new c();
}
class d extends AA {
constructor() {
super();
}
getMember() {
return this.member;
}
}
class e {
}
</pre>
<p>제네릭 역시 transpile과정에서 소모되고 js에선 사라진다.</p>
</body>
</html>