JavaScript에서 함수를 선언해보자!
// named function
function namedAdd(x, y) {
return x + y;
}
// anonymous function
let anonymousAdd = function(x, y) { return x + y };
// arrow function
let arrowAdd = (x, y) => x + y ;
이렇게 기명함수, 익명함수와 ES6에서 추가된 화살표 함수까지 선언해보았다.
이제 똑같은 함수를 TypeScript로 선언해보면서 TypeScript의 함수의 특징에 대해 알아보자.
// named function
function namedAdd(x: number, y: number): number {
return x + y;
}
// anonymous function
let anonymousAdd = function(x: number, y: number): number { return x + y };
// arrow function
let arrowAdd = (x: number, y: number):number => x + y ;
함수의 파라미터 부분을 잘 보면,
(x: number, y: number)
: number
이렇게 함수의 매개변수나 반환 타입을 추가해서 타입 안정성을 강화한 함수를 선언적 함수라고 부른다.
TypeScript는 반환문을 보고 반환될 값의 타입을 추론할 수 있다. 즉, 반환 타입을 생략할 수도 있다.
( ex : 위 예시는 number + number 이므로 반환 타입은 무조건 number! )
만약 함수에서 아무것도 반환하지 않아야 한다면 반환 타입에 void
를 명시하면 된다.
function returnNothing(): void {
console.log('나는 그냥 console만 출력하는 함수');
}
TypeScript 에서는 함수에 작성한 모든 파라미터를 필수 파라미터라고 가정한다.
쉽게 말해서, 함수를 정의할 때 지정한 파라미터의 갯수와 호출할 때 실제로 넘겨주는 인자의 갯수가 일치해야 한다.
파라미터로
null
이나undefined
를 지정할 수 없다는 의미가 아니다!
function defaultParams (name: string, age: number) {
return `hi~ my name is ${name} and ${age} years old.`;
}
let ok = defaultParams("solmi", 26); // 200 OK
let error = defaultParams("solmi") // error (함수의 파라미터보다 인자가 더 적음)
let error2 = defaultParams("solmi", 26, "love you") // error (함수의 파라미터보다 인자가 더 많음)
JavaScript에서는 모든 파라미터가 선택적이었는데, TypeScript에서도 파라미터를 선택적으로 이용하려면 어떻게 해야 할까?
파라미터의 이름 끝에 ? 를 붙이면 해결할 수 있다!
function defaultParams(name: string, age?: number) {
if (age) return `hi~ my name is ${name} and ${age} years old.`;
else return `hi~ my name is ${name}.`;
}
let ok = defaultParams("solmi", 26); // 200 OK
let ok2 = defaultParams("solmi") // 200 OK
let error = defaultParams("solmi", 26, "love you") // error (함수의 파라미터보다 인자가 더 많음)
단, 선택적 파라미터를 사용할 경우, 필수 파라미터보다 앞에 올 수 없다!
예를 들어 위의 예시에서 age
대신 name
을 선택적으로 사용하고 싶다면..
function defaultParams(name?: string, age: number) { 대충 문자열 반환하는 함수 }
이렇게 작성할 수 없다.
function defaultParams(age: number, name?: string) { 대충 문자열 반환하는 함수 }
이렇게 선택적 파라미터가 파라미터 제일 끝에 가도록 순서를 변경해줘야 한다.
인자를 전달하지 않거나 undefined
를 전달했을 때에 기본값으로 할당될 파라미터의 값을 정해놓을 수 있는데, 이를 기본 초기화 파라미터라고 부른다.
👉 선택적 파라미터에서는 사용할 수 없다.
왜🤷🏻♀️? 선택적 파라미터는 필요에 따라 인자를 전달하거나 전달하지 않아서 각각의 경우의 로직을 짤 수 있는 반면에,
기본 초기화 파라미터는 인자가 전달되면 전달받은 인자를, 전달되지 않으면 정해진 기본값을 사용하기 때문에 선택적 파라미터와 충돌한다!
처음에 사용했던 예시를 다시 보면서 이어서 설명!!
function defaultParams(name: string, age: number = 99) {
if (age) return `${name} and ${age}`;
else return `name is ${name}.`;
}
let ok = defaultParams("solmi", 26); // solmi and 26
let ok2 = defaultParams("solmi", undefined); // solmi and 26 => undefined를 지정했는데 기본값인 99를 전달받아서 정상적으로 값이 나온다!
let ok3 = defaultParams("solmi") // solmi and 99 => name is solmi를 return하고 싶었지만, 기본값인 99를 전달받아서 원하던 것과 다른 결과가 나왔다!
let error = defaultParams("solmi", 26, "love you") // error (함수의 파라미터보다 인자가 더 많음)
참고로 위 예시에서
(name: string, age: number = 99)
부분은(name: string, age = 99)
이렇게 기본 초기화 파라미터의 타입을 생략해서 작성할 수 있다.
기본값에 숫자99
가 지정되었기 때문에,age: number
라고 TypeScript가 타입을 추론할 수 있기 때문!
( 사실 더 정확히는age: number | undefined
타입이다! )
또, 기본 초기화 파라미터는 선택적 파라미터와 달리 기본 파라미터보다 뒤에 와야만 하는건 아니다.
기본 파라미터의 앞에 와도 정상적으로 동작한다.
JavaScript의 ES6부터 추가된 구문으로, 정해지지 않은 인수를 전개 연산자를 이용해 다수의 파라미터를 배열로 나타낼 수 있게해준다.
function sum(...theArgs) {
return theArgs.reduce((previous, current) => {
return previous + current;
});
}
이런식으로 사용한다!
TypeScript에서도 마찬가지로 나머지 파라미터가 있다.
다수의 파라미터를 그룹지어서 활용할 필요가 있을 때, 혹은 얼마나 많은 파라미터를 받을지 알 수 없을 때 주로 사용한다.
단, JavaScript에는 배열이라는 type이 없지만, TypeScript는 배열의 type을 명시해줘야 하기 때문에 아래와 같이 작성해야 한다.
function intro(name: string, ...likes: string[]) {
return `$my name is ${name}, i like ${likes.join(" ")}!`;
}
let introduction = intro("solmi", "coding", "beer", "movie", "game"); // my name is solmi, i like coding beer movie game!
let introduction2 = intro("solmi"); // my name is solmi, i like!
introduction
에서 "coding", "beer", "movie", "game"
이라는 인자들을 likes
라는 하나의 변수로 모았다!
likes
는 배열이기 때문에, 위 예시의 join
처럼 배열 메서드를 활용할 수 있다.
한가지 재밌는 점은, introduction2
에서 보는바와 같이 나머지 매개변수에 아무것도 전달하지 않아도 error가 나지않고 정상적으로 작동한다는 점이다.
즉, 나머지 파라미터는 선택적 파라미터... 나아가 선택적 파라미터x무한 이라고 말할 수 있다.
0부터 무한까지 원하는 만큼 넘겨줄 수 있기 때문!
함수 오버로드란, 함수명은 같지만 파라미터와 반환 타입이 다른 함수를 여러개 선언하는 것을 말한다.
그게 대체 뭔말일까?? 우선 JavaScript 코드를 먼저 보자!
function add(a, b) {
return a + b;
}
let isString = add('1', '3'); // '13'
let inNumber = add(1, 3); // 4
JavaScript는 타입이 동적으로 정해지기 때문에 위와 같이 하나의 함수에 타입이 다른 인자를 전달해도 문제 없이 계산된다.
이때 함수의 return 값은 전달된 인자의 형태에 따라 결정된다.
이제 type이 정적으로 명시되어있는 TypeScript에서 위의 add
함수를 작성해보자!
위의 예시처럼 숫자만 더해주는 함수가 아닌, 인자로 srting이 들어오거나 각 인자의 타입이 다른 경우에도 에러 없이 컴파일되는 함수를 만들고 싶다면, 아래처럼 작성하면 된다.
function add(a: string, b:string): string;
function add(a: number, b:number): number;
function add(a: any, b: any): any {
return a + b;
}
let isString = add('1', '3'); // '13'
let inNumber = add(1, 3); // 4
위의 add
함수의 목록을 오버로드 목록이라고 부른다.
JavaScript로 컴파일 되는 과정에서 컴파일러가 오버로드 목록의 위부터 아래로 내려가며 가장 적합한 오버로드를 선택해 작업을 수행한다.
그렇기 때문에 가장 일반적인(위 예시에서 파라미터를 any 타입으로 선언한 add
함수) 함수를 가장 아래에 선언하고, 가장 구제적인 함수는 가장 위에 선언하는 방식으로 오버로드 리스팅을 해야한다.
any
타입으로 함수를 선언하면 안될까? 직접 코드를 보자!
function add(a: any, b: any): any {
return a + b;
}
let isString = add('1', '3');
let inNumber = add(1, 3);
오~? 그냥 any
타입으로 해도 잘만 나오는데??
하지만, 이렇게 되면 isString
과 inNumber
의 type은 어떻게 될까?
당연히 isString
은 string, inNumber
는 number이겠지? 하고 확인해보면!!
엇!!! 둘 다 type이 any
로 되어있다.
function add(a: any, b: any): any {
return a + b;
}
let isString = add('1', '3'); // '13'
inString = add(10, 30); // 40
실제로 이렇게 전혀 다른 타입을 isString
에 재할당해도 문제없이 넘어가버린다.
그럼, 오버로드로 각 매개변수와 반환 타입을 여러개 선언해놨을땐 어떻게 될까?
오오오~ 각각 의도했던 대로 타입이 잘 들어가있다.
let isString = add('1', '3'); // '13'
inString = add(10, 30); // error!
이렇게 다른 타입을 isString
에 재할당하면, 당연히 error가 난다!
함수는 이정도로 하고 마무리!! TypeScript Handbook에 this등 더 많은 내용이 정리되어 있다! 더 공부하고 싶다면 위 링크로 고고띵 =3
출처 : typescript Handbook, https://doitnow-man.tistory.com/174
개발 왕초보 코린이입니다!
이 내용은 각종 강의&구글링을 통해 배운 내용을 정리하는 것으로, 제가 이해하고 넘어간 개념이 틀렸거나 더 보충할 개념이 있다면 댓글 남겨주시면 정말 감사하겠습니다!!