From 6223343039dd226991f570a3ad3fa165ce8354b5 Mon Sep 17 00:00:00 2001 From: d5ng Date: Sat, 22 Mar 2025 00:00:02 +0900 Subject: [PATCH 1/3] =?UTF-8?q?=E2=9C=A8=20Feat:=20bind=20=ED=95=A8?= =?UTF-8?q?=EC=88=98=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- assignment/src/bind.test.ts | 28 ++++++++++++++++++++++++++++ assignment/src/bind.ts | 21 +++++++++++++++++++++ 2 files changed, 49 insertions(+) create mode 100644 assignment/src/bind.test.ts create mode 100644 assignment/src/bind.ts diff --git a/assignment/src/bind.test.ts b/assignment/src/bind.test.ts new file mode 100644 index 0000000..3a79eb4 --- /dev/null +++ b/assignment/src/bind.test.ts @@ -0,0 +1,28 @@ +import { bind } from "./bind" + +describe("bind 함수 테스트", () => { + test("bind Partial", () => { + function greet(this: { name: string }, greeting: string, punctuation: string) { + return `${greeting}, ${this.name}${punctuation}` + } + + const person = { name: "Alice" } + const greetAlice = bind(greet, person, "Hello") + + expect(greetAlice("!")).toBe("Hello, Alice!") + }) + + test("생성자 함수 테스트", () => { + // 즉 생성자 함수를 사용할 때에도 this binding이 되야함 + // 어떻게? + function Person(this: Record, name: string) { + this.name = name + } + + const BoundPerson = bind(Person, { name: "notUsed" }) + const p = new BoundPerson("Tom") + + expect(p.name).toBe("Tom") + expect(p instanceof Person).true + }) +}) diff --git a/assignment/src/bind.ts b/assignment/src/bind.ts new file mode 100644 index 0000000..571361f --- /dev/null +++ b/assignment/src/bind.ts @@ -0,0 +1,21 @@ +type BindThis = T extends (this: any, ...args: infer A) => infer R ? (this: U, ...args: A) => R : never + +type PartiallyBound = T extends (...args: [...P, ...infer Rest]) => infer R + ? (...args: Rest) => R + : never + +export function bind any, U, P extends any[]>(fn: T, thisArg: U, ...args: P) { + function boundFn(...args2: any[]) { + const isInstnace = this instanceof boundFn + + if (isInstnace) { + return fn.call(this, ...args, ...args2) + } + + return fn.call(thisArg, ...args, ...args2) as PartiallyBound, P> + } + + boundFn.prototype = Object.create(fn.prototype) + + return boundFn +} From c015341903098959cf79ec16b76b9253566078e2 Mon Sep 17 00:00:00 2001 From: d5ng Date: Sat, 22 Mar 2025 00:04:51 +0900 Subject: [PATCH 2/3] =?UTF-8?q?=E2=9C=85=20Test:=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EC=BD=94=EB=93=9C=20=EC=B6=94=EB=9D=BC=20(Binding)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- assignment/src/bind.test.ts | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/assignment/src/bind.test.ts b/assignment/src/bind.test.ts index 3a79eb4..9e61f3b 100644 --- a/assignment/src/bind.test.ts +++ b/assignment/src/bind.test.ts @@ -1,6 +1,17 @@ import { bind } from "./bind" describe("bind 함수 테스트", () => { + test("bind Basic", () => { + const users = { name: "d5ng" } + + function getName(this: { name: string }) { + return `내 이름은 ${this.name}이에요!` + } + + const bindingUser = bind(getName, users) + expect(bindingUser()).toBe("내 이름은 d5ng이에요!") + }) + test("bind Partial", () => { function greet(this: { name: string }, greeting: string, punctuation: string) { return `${greeting}, ${this.name}${punctuation}` @@ -13,8 +24,6 @@ describe("bind 함수 테스트", () => { }) test("생성자 함수 테스트", () => { - // 즉 생성자 함수를 사용할 때에도 this binding이 되야함 - // 어떻게? function Person(this: Record, name: string) { this.name = name } From 94a9a9b53f8ec9ba48875c7e6127254280aa86c1 Mon Sep 17 00:00:00 2001 From: d5ng Date: Sun, 23 Mar 2025 18:31:57 +0900 Subject: [PATCH 3/3] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Refactor:=20boundFn=20?= =?UTF-8?q?=ED=83=80=EC=9E=85=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- assignment/src/bind.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assignment/src/bind.ts b/assignment/src/bind.ts index 571361f..9773ac0 100644 --- a/assignment/src/bind.ts +++ b/assignment/src/bind.ts @@ -5,7 +5,7 @@ type PartiallyBound = T extends (...args: [...P, ...infer Re : never export function bind any, U, P extends any[]>(fn: T, thisArg: U, ...args: P) { - function boundFn(...args2: any[]) { + function boundFn(this: any, ...args2: any[]) { const isInstnace = this instanceof boundFn if (isInstnace) {