More On Functions๐
ํ์ ์คํฌ๋ฆฝํธ์์ ํจ์๋ฅผ ๋ค๋ฃจ๋ ๋ฒ์ ์์๋ณด์
Function Type Expressions
ํ์ ์คํฌ๋ฆฝํธ์์ fuction์ ํํํ ๋ ๊ธฐ๋ณธ์ ์ผ๋ก parameter์ return ๊ฐ์ ๋ํด ํ์ ์ผ๋ก ํํํ๋ค. Parameter type์ ๊ฒฝ์ฐ ํ์ ์ ์ ํด์ฃผ์ง ์์ผ๋ฉด any๋ก ์ ํด์ง๋ค.
function greeter(fn: (a: string) => void) {
fn("Hello, World")
}
function printToConsole(s: string) {
console.log(s)
}
greeter(printToConsole)Call Signatures
์๋ฐ์คํฌ๋ฆฝํธ์์ ํจ์๋ ๊ฐ์ฒด๋ค. ์ด์ ์ด ์ค์ํ ์ ์ ํจ์๊ฐ ์์ฑ์ ๊ฐ์ง ์ ์๋ค๋ ์๋ฏธ์ด๊ธฐ ๋๋ฌธ์ธ๋ฐ, function type annotation์์๋ ์์ฑ์ ํ ๋นํ์ง ๋ชปํ๊ฒ ํ๋ค. ์์ฑ์ ํ ๋นํ๊ณ ์ถ๋ค๋ฉด ํด๋น ์์ฑ์ ๋ํ call signature๋ฅผ ํ ๋นํด์ผ ํ๋ค.
type DescribableFunction = {
description: string
(someArg: number): boolean
}
function doSomething(fn: DescribableFunction) {
console.log(fn.description + " returned " + fn(6))
}
function myFunc(someArg: number) {
return someArg > 3
}
myFunc.description = "default description"
doSomething(myFunc)Construct Signatures
์๋ฐ์คํฌ๋ฆฝํธ์์ ํจ์ ์ ์ธ๋ฌธ์ผ๋ก ์ ์๋ ํจ์๋ ๋ชจ๋ ์์ฑ์ ํจ์๋ก ์ฐ์ผ ์ ์๊ธฐ ๋๋ฌธ์ new ํค์๋๊ฐ ์ฌ์ฉ๋ ์ ์๋ค.newํค์๋๋ฅผ ์ด์ฉํ ํ์
์ ์๋ฅผ ํตํด construct signature๋ฅผ ์ ์ํ ์ ์๋ค.
type SomeConstructor = {
new (s: string): SomeObject
}
function fn(ctor: SomeConstructor) {
return new ctor("hello")
}Generic Functions
๋ณดํต param์ ํ์ ๊ณผ ๋ฐํ๊ฐ์ ํ์ ์ ๊ด๋ จ์ด ์๊ฑฐ๋ param๋ค๊ฐ์ ํ์ ์ด ๊ด๊ณ๊ฐ ์๋ค. any๋ฅผ ์ฌ์ฉํ์ง ์๊ณ ์ฐ๋ฆฌ๊ฐ ์ํ๋ ํ์ ์ผ๋ก ์ขํ์ ์ฌ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ์ผ๋ก generic์ ์ด์ฉํ ์ ์๋ค.
function firstElement<Type>(arr: Type[]): Type | undefined {
return arr[0]
}
// s is of type 'string'
const s = firstElement(["a", "b", "c"])
// n is of type 'number'
const n = firstElement([1, 2, 3])
// u is of type undefined
const u = firstElement([])inference
inference๋ ํ์ ์ ์ง์ ์ ํ๋ ๊ฒ์ ์๋์ง๋ง typescript๋ฅผ ํตํด ์ถ๋ก ๋๋ ํ์ ์ ์๋ฏธํ๋ค.
function map<Input, Output>(
arr: Input[],
func: (arg: Input) => Output
): Output[] {
return arr.map(func)
}
const parsed = map(["1", "2", "3"], n => parseInt(n)) // parsedsms number[]์ด์ผConstraints์ ์ค๋ฅ
generic์ ์ด์ฉํด์ ์ฐ๊ด์๋ input ํ์ ๋ค์ ๊ด๊ณ๋ฅผ ์ ์ํ์ง๋ง ์ด๋์ ๋ ์ฐ๋ฆฌ๊ฐ ์ํ๋ ํ์ ์ผ๋ก ์ขํ ์ ์๋ค. ์ขํ ๋๋ extends๋ฅผ ํตํด ํด๋น ์์ฑ์ ๊ฐ์ง๊ณ ์๋ ํ์ ๋ฑ์ผ๋ก ์ขํ ์ ์๋ค.
์ด๋ฐ Generic์ ์ด์ฉํ ํ์ ์ขํ๊ธฐ๋ ์ ์ฉํ ์ ์์ง๋ง ์กฐ์ฌํด์ผํ ๋ถ๋ถ์ด ์๋ค.
์ ์ฝ๋์์ ์๋ฌ๊ฐ ๋ ์ด์ ๋ ์ฐ๋ฆฌ Generic์ผ๋ก ์ ๋ฌํ ์ธ์์ ํ์ ์ด ๋ฐํ๊ฐ์ผ๋ก ๊ทธ๋๋ก ๋ฐํ๋ ๊ฒ๋ผ๊ณ ์ ์ธํ๋ค. ํ์ง๋ง else๋ฌธ ์์๋ ์ขํ์ง ๋ฒ์์ ๊ฐ์ฒด๋ฅผ ๋ฐํํ๊ธฐ ๋๋ฌธ์ ๊ธฐ์กด๊ณผ ๋ค๋ฅธ ํ์ ์ด๊ธฐ ๋๋ฌธ์ ํ์ ์๋ฌ๊ฐ ๋ฌ๋ค. ํ์ ์คํฌ๋ฆฝํธ์์ ํฐ ์งํฉ์ ์์ ์งํฉ์ ํ ๋น๋ ์ ์์ง๋ง, ๊ทธ๋ ๋ค๊ณ ํฐ์งํฉ์ด ์์ ์งํฉ์ด๋ผ๊ณ ํ ์๋ ์๋ค.
์ฌ์๋ ๋๋ฌผ์ ํฌํจ๋๋ค ๋ผ๋๋ง์ ์ฌ์๊ฐ ๋๋ฌผ์ ํฌํจ๋๊ธฐ ๋๋ฌธ์ ๋ง์ง๋ง, ์ฌ์์ ๋๋ฌผ์ ๊ฐ๋ค๋ผ๋ ๋ง์๋ ์ค๋ฅ๊ฐ ์๋ ๊ฒ๊ณผ ๊ฐ๋ค.
Guidelines for Writing Good Generic Functions
Generic ํจ์๋ฅผ ์ ์์ฑํ๋ ๋ฐฉ๋ฒ 3๊ฐ์ง๋ฅผ ์ ๋ฆฌํด๋ณด์.
- Push Type Param Down: param์ ๋ ๊ตฌ์ฒด์ ์ธ ๊ฐ์ผ๋ก ์ฌ์ฉํ๋ค.
function firstElement1<Type>(arr: Type[]) {
return arr[0]
}
function firstElement2<Type extends any[]>(arr: Type) {
return arr[0]
}
// a: number (good)
const a = firstElement1([1, 2, 3])
// b: any (bad)
const b = firstElement2([1, 2, 3])- Use Fewer Type Parameters: ๋ ์ ์ ํ์ ์ param์ผ๋ก ์ด์ฉํ๋ค.
function filter1<Type>(arr: Type[], func: (arg: Type) => boolean): Type[] {
return arr.filter(func)
}
function filter2<Type, Func extends (arg: Type) => boolean>(
arr: Type[],
func: Func
): Type[] {
return arr.filter(func)
}filter2์ ๊ฒฝ์ฐ๋ ์ด๋ค ํจ์ ํ์ ์ธ์ง ์ผ์ผ์ด ์ ํด์ค์ผํ๋ฏ๋ก ์ฌ์ฉ์ฒ์์ ๋ถํธํจ์ด ์กด์ฌํ๋ค.
- Type Parameters Should Appear Twice: ์ฌ์ฌ์ฉ์ด ํ์ํ ์ํฉ์๋ง ์ ๋ค๋ฆญ์ ์ฐ์.
function greet<Str extends string>(s: Str) {
console.log("Hello, " + s)
}
greet("world")
function greet(s: string) {
console.log("Hello, " + s)
}ํจ์ฌ ๊ฐ๋จํ๊ฒ ์ฌ์ฉํ ์์๋ ๋ฐฉ๋ฒ์ ๊ณ ๋ฏผํด๋ณด๊ณ , ๋ฐ๋ณต๋๋ ํ์ ์ ํํด์ ์ฌ์ฌ์ฉ์ ์ํด ์ ๋ค๋ฆญ์ ์ฐ์.
Optional Parameters
param์ด ์์ ์ ์๋ ๊ฒฝ์ฐ๋ฅผ ์ํด ?๋ฅผ ์ด์ฉํ ์ ์๋ค. ์ด๋ ๊ฒ ์ฌ์ฉํ๊ฒ ๋๋ฉด T|undefined ๋ก ํ์
์ด ํ ๋น๋๋ค.
function f(x?: number) {
// ...
}
f() // OK
f(10) // OK๋๋ param์ด ์์ ๋๋ฅผ ์ํ ๊ธฐ๋ณธ ๊ฐ์ parameter default๋ก ์ ์ํ ์ ์๋ค.
function f(x = 10) {
// ...
}์ฃผ์ํ ์ ์ callback์ ์ด์ฉํ ๋์ ์๋ฏธ๋ optionalํ parameter๋ ํ์์์ด ํธ์ถ ๋ ์ ์์์ ์๋ฏธํ๋ ๊ฒ์ด๋๊น ๋ถํ์ํ๊ฒ ์ฌ์ฉํ์ง ๋ง์.
Function Overloads
ํจ์ ์ค๋ฒ๋ก๋๋ ํ์์ ์ ์ฌ์ฉํ์ง ์๋ ๋ถ๋ถ์ด๋ค ๋ณด๋ ์ดํดํ๋๋ฐ ์ด๋ ค์์ด ์์๋ค. ํจ์ Overload๋ ๊ฐ์ ์ด๋ฆ์ ํจ์์ param์ด ๋ค๋ฅด๊ฒ ์ ์ํ๋ ๋ฐฉ๋ฒ์ด๋ค.
function makeDate(timestamp: number): Date
function makeDate(m: number, d: number, y: number): Date
function makeDate(mOrTimestamp: number, d?: number, y?: number): Date {
if (d !== undefined && y !== undefined) {
return new Date(y, mOrTimestamp, d)
} else {
return new Date(mOrTimestamp)
}
}
const d1 = makeDate(12345678)
const d2 = makeDate(5, 5, 5)Overload ํจ์๋ฅผ ์์ฑํ๋๋ฐ์๋ ๋ช๊ฐ์ง ๊ท์น์ด ์๋ค.
- ์ธ์๊ฐ ์์ ๋์ ์ด๋ค ํจ์์ธ์ง ๊ตฌํ์ด ํ์ํ๋ค.
์ ์์ ์์ ์๋ฌ๊ฐ ๋ฐ์ํ ์ด์ ๋ param์ด ์์ ๋์ ํจ์๊ฐ ์ด๋ป๊ฒ ๊ตฌํ๋ ์ง ์ ์๋์ง ์์๊ธฐ ๋๋ฌธ์ด๋ค.
์๋์ ๊ณ ์น๋ฉด ํ์ ์๋ฌ๊ฐ ์ฌ๋ผ์ง๋ ๊ฒ์ ๋ณผ ์ ์๋ค.
function fn(x: string): void
function fn(): void
function fn() {
// ...
}
// Expected to be able to call with zero arguments
fn()- Overload ๋ผ๋ฆฌ compatibleํด์ผํ๋ค.
์ ์์ ์์ ๊ฐ์ param ๊ฐฏ์๋ฅผ ๊ฐ์ง๋ overload ํจ์๋ฅผ ์์ฑํ๋ค. ํ์
์๋ฌ๊ฐ ๋ฐ์ํ ์ด์ ๋ ๋จผ์ ์์ฑํ overload ํจ์ param ํ์
์ด boolean์ผ๋ก ์ ์๋ ์ํฉ์์ ๊ฐ์ param ๊ฐฏ์๋ฅผ ๊ฐ์ง๋ ๋๋ฒ์งธ overload ํจ์์์ booleanํ์
๊ณผ compatible ํ์ง ์์ string ํ์
์ผ๋ก ์ ์ํ๊ธฐ ๋๋ฌธ์ด๋ค.
- Overload ํจ์๋ ์กฐ๊ฑด๋ถ๋ก ์ฐ์ด๋ฉด ์๋๋ค.
function len(s: string): number
function len(arr: any[]): number
function len(x: any) {
return x.length
}์ ์์ ๋ string๊ณผ array๋ฅผ param์ผ๋ก ๋ฐ์ ์ ์๋ ํจ์ overload๊ฐ ์ ์๋ ์ํฉ์ด๋ค.
์ ํ์ ์๋ฌ๋ ์กฐ๊ฑด์ ๋ฐ๋ผ ๋ค๋ฅธ ํ์ ์ param์ ์ ๋ฌํ๋ ์ํฉ์ด๊ธฐ ๋๋ฌธ์ ๋ฐ์ํ๋๋ฐ, ๊ทธ ์ด์ ๋ ํ์ ์คํฌ๋ฆฝํธ๋ ํ๋์ overLoad์์๋ง ํจ์๋ฅผ ํธ์ถํ๊ธฐ ๋๋ฌธ์ด๋ค. ์ด๋ด๋๋ param์ ์ ์ํ ๋ union type์ผ๋ก ์ ์ํ๋ ๊ฒ ๋ ์ฌ๋ฐ๋ฅธ ๋ฐฉ๋ฒ์ด๋ค.
function len(x: any[] | string) {
return x.length
}this ๋ค๋ฃจ๊ธฐ
javascript์์์ this ์ฒ๋ผ typescript์ this๋ ๋์ ์ผ๋ก ์ ์๋๋ค.
const user = {
id: 123,
admin: false,
becomeAdmin: function () {
this.admin = true
},
}์ ์์ ์์ this๋ ์์์ ๋ฐ์ธ๋ฉ์ ์ํด ํธ์ถ๋๋ ์์น์ ๋ฐ๋ผ ๋ค๋ฅธ ๊ฐ์ ์๋ฏธํ๊ฒ๋๋ค.
์ด๋ฌํ this๋ฅผ ์๋์ ์ผ๋ก ์ฝ๊ฒ(?) ์ ์ํ๋ ๋ฐฉ๋ฒ์ผ๋ก ํ์ดํํจ์๋ฅผ ์ด์ฉํ๋ ๋ฐฉ๋ฒ์ด ์๋ค. ํ์ดํ ํจ์๋ ํจ์ ์ ์ธ์๊ณผ ๋ค๋ฅธ ํน์ง์ด ์๋๋ฐ ๊ทธ์ค ์์ฑ์ ํจ์๋ก ์ฐ์ผ ์ ์๋ค๋ ์ ์ด ์๋ค. ๊ทธ๋ ๊ธฐ ๋๋ฌธ์ ์์ฒด์ ์ธ this๋ฅผ ๊ฐ์ง์ง ์๊ณ ํ์ดํ ํจ์์์ this๋ ์์ ์ค์ฝํ์ this๋ฅผ ์ฐธ์กฐํ๋ ๊ท์น ๊ฐ์ง๋ค.
Other Types to Know about
๋ช๊ฐ์ง ์์ ์๊ฐ๋์ง ์์๋ ํ์ ๋ค์ ๋ํด ์ ๋ฆฌํด๋ณด์.
- Void
ํจ์์์ ๋ฐํํ๋ ๊ฐ์ด ์์ ๋๋ฅผ ์ํ ํ์ ์ผ๋ก, return ๋ฌธ์ด ์์ ๋ ์๋์ผ๋ก undefined์ด ๋ฐํ๋์ง๋ง ํ์ ์คํฌ๋ฆฝํธ์์๋ ๋ฐ๋ก void๋ก ์ ์ํ๋ค.
- unknown
any์ ์ ์ฌํ์ง๋ง, any์ ๋ฌ๋ฆฌ ์ด๋ค ์์ฑ์ ๊ฐ์ง๋ ์ง ์ ์ ์๊ธฐ ๋๋ฌธ์ ์์ฑ์ ์ ๊ทผํ ์ ์๋ค. ์ฃผ๋ก try-catch ๋ฌธ์ผ๋ก ์๋ฌ๋ฅผ ๋ฐ์ ๋ unknown์ผ๋ก ๋ฐํ๋๊ธฐ ๋๋ฌธ์ ๋น์ฆ๋์ค ์๋ฌ๋ก ์ ์ ํ๊ฒ ํ์
์ ์ ์ํ ํ instanceOf ๋ฅผ ์ด์ฉํด ์๋ฌ ๊ฐ์ฒด๋ฅผ ์ ์ํ๋ ๋ฐฉ์์ผ๋ก ํ์
์์ ์ฌ์ฉํ๊ณ ์๋ค.
- never
never๋ ์ด๋ค ๊ฒ๋ ํฌํจ๋ ์ ์๋ ํ์ ์ ์๋ฏธํ๋ค. union์ด๋ switch๋ฌธ์์ ๋์ด์ ์๋ค๋ ๊ฒ์ ์๋ฏธํ๋ค.
function fn(x: string | number) {
if (typeof x === "string") {
// do something
} else if (typeof x === "number") {
// do something else
} else {
x // has type 'never'!
}
}Rest Parameters and Arguments
Rest Parameter๋ ์ธ์๊ฐ ๋์ ์ผ๋ก ๋ค์ด์ฌ ๋์ param์ ์๋ฏธํ๋ค. arguments๋ก ๋ฐ์ param์ ํ์ ๋ค์ ์ ์ํ ์ ์๋ค.
function multiply(n: number, ...m: number[]) {
return m.map(x => n * x)
}
// 'a' gets value [10, 20, 30, 40]
const a = multiply(10, 1, 2, 3, 4)rest parameter๋ฅผ ์๊ธธ ์ ์๋ ํ์ ์๋ฌ๋ก๋ ๋ฐฐ์ด๊ณผ ํํ์ ํ์ ์ฐจ์ด์์ ๋ฐ์ํ ์ ์๋ค.
์ ์์ ์์ Math.atan2(...)๋ฉ์๋๋ ๋ฑ ๋๊ฐ์ ์ธ์๋ฅผ ๋ฐ์ง๋ง args๋ number[]๋ก ํ์
์ด ๋์ด์๊ธฐ ๋๋ฌธ์ ๋ช๊ฐ์ ๊ฐ์ด ๋ ๋ค์ด์ฌ์ง ๋ชจ๋ฅด๋ ํ์
์ ์๋ฏธํด ์๊ธด ํ์
์๋ฌ๋ค.
์ด๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด์๋ ๋ฐฐ์ด์ด ์๋๋ผ ๋ช๊ฐ์ ์์๋ก ๋์ด์๋ ํ์ ์ธ์ง ์ ์๋ tuple์ ์ด์ฉํ๋ฉด ํด๊ฒฐํ ์ ์๋ค.
const args = [8, 5] as const
// OK
const angle = Math.atan2(...args)Parameter Destructuring
๊ฐ์ฒด param์ ์ ๋ฌํ ๋ ๊ฐ ์์ฑ์ ๋ํ ํ์ ์ ์ ์ํด์ ์ ๋ฌํ ์ ์๋ค.
type ABC = { a: number; b: number; c: number }
function sum({ a, b, c }: ABC) {
console.log(a + b + c)
}Assignability of Functions
void๋ฅผ ๋ฐํํ์ ์ผ๋ก ๊ฐ์ง๋ ํจ์๋ค ๋ผ๋ฆฌ ๊ฐ์ง๋ ํน์ดํ ํน์ง์ด ์๋ค. void ์์ฒด๋ ํด๋น ํจ์๋ค์ด ๋ฐํํ๋ ํ์ ์ ๋ํด ๊ฐํ๊ฒ ํ์ ์ ๋ฐ์ง์ง ์๊ธฐ ๋๋ฌธ์ ๋ฐํ ํ์ ์ด ๋ฌด์๋๋ค.
type voidFunc = () => void
const f1: voidFunc = () => {
return true
}
const f2: voidFunc = () => true
const f3: voidFunc = function () {
return true
}์ ์์ ์์ f1,f2,f3 ๋ค ๋ฐํํ๋ ํ์
์ด boolean์ด์ง๋ง voidFunc๋ก ์ ์ํด๋ ํ์
์๋ฌ๊ฐ ๋ฐ์ํ์ง ์๋๋ค.
function f2(): void {
return true // ์๋ฌ ๋ฐ์
}ํ์ง๋ง ์ง์ ์ ์ํ ๋ void๋ฅผ ๋ฐํํ๋ค๊ณ ์ ์ํ ์์ ํ์ ์๋ฌ๊ฐ ๊ฑธ๋ฆฌ๊ฒ ๋๋ค.