diff --git a/assignment/src/bind.test.ts b/assignment/src/bind.test.ts new file mode 100644 index 0000000..9e61f3b --- /dev/null +++ b/assignment/src/bind.test.ts @@ -0,0 +1,37 @@ +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}` + } + + const person = { name: "Alice" } + const greetAlice = bind(greet, person, "Hello") + + expect(greetAlice("!")).toBe("Hello, Alice!") + }) + + test("생성자 함수 테스트", () => { + 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..9773ac0 --- /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(this: any, ...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 +}