0. 함수타입
자바스크립트 함수가 있을 때, 이 함수를 다른 사람에게 설명하는 가장 좋은 방법은
이 함수가 어떤 매개변수를 받고 어떤 값을 반환 하는지 이야기 하는 것 입니다.
그럼 타입스크립트에서는 어떨까요?
어떤 타입의 매개변수를 받고, 어떤 타입의 값을 반환하는지 이야기 하면 됩니다.
/**
* 함수의 타입 정의하기
*/
//함수를 설명하는 가장 좋은 방법
// 어떤 매개변수를 받고, 어떤 결과값을 반환하는 지 이야기
// 어떤 [타입의] 매개변수를 받고, 어떤 [타입의] 결과값을 반환하는 지 이야기
function func(a:number, b:number){
return a+b;
//function func(a: number, b: number): number
//return 문을 보고 함수 타입을 추론함
}
/**
* 화살표함수의 타입을 정의하는 방법
*/
const add = (a:number, b:number) => a+b;
/**
* 함수의 매개변수
*/
function introduce(name = "정지은", tall?:number){ //name: string
console.log(`name : ${name}`)
if(typeof tall === "number"){
console.log(`tall : ${tall +10}`) //'tall'은(는) 'undefined'일 수 있습니다. => 조건문으로 타입가드를 만들어서 타입 좁히기
}
}
introduce("정지은", 163);
introduce("정지은") // 2개의 인수가 필요한데 1개를 가져왔습니다. = > 선택적(?) 매개변수 사용
// 선택적(?) 매개변수 쓸때 주의할점
// 선택적(?) 매개변수는 필수 매개변수 앞에 오면 X
function getSum(...rest: number[]){// ...rest 펼쳐져서 배열에 각각 담긴다 [1,2,3,4]
let sum =0;
rest.forEach((it)=> (sum += it))
return sum;
}
getSum(1,2,3) //6
getSum(1,2,3,4,5) //15
//매개변수를 튜플 타입(길이가 정해져있는)으로도 만들 수 잇음
function getSum2(...rest: [number, number, number]){ //...rest 펼쳐져서 배열에 각각 담긴다 [1,2,3,4]
let sum =0;
rest.forEach((it)=> (sum += it))
return sum;
}
getSum2(1,2,3) //6
getSum2(1,2,3,4,5) //15, 오류: 3개의 인수가 필요한데 5개를 가져왔습니다.
1. 함수 타입 표현식과 호출 시그니쳐
다음과 같이 함수 타입을 타입 별칭과 함께 별도로 정의할 수 있습니다.
이를 함수 타입 표현식(Function Type Expression)이라고 부릅니다.
더불어, 호출 시그니쳐(Call Signature)는 함수 타입 표현식과 동일하게 함수의 타입을 별도로 정의하는 방식입니다.
/**
* 함수 타입 표현식과 호출시그니쳐
* => 함수의 타입을 별도로 정의(타입별칭사용)하는 방법
*/
type Operation = (a:number, b:number) => number; // 함수타입 표현식 사용, 범용적 사용하기 굳
const add0 = (a:number, b:number):number => a + b; // 타입별칭이 없다면
const add1: Operation = (a, b)=> a + b;
const sub: Operation = (a,b) => a=b;
const multiply:Operation = (a,b) => a* b;
const divide: Operation = (a,b) => a / b;
/**
* 호출(콜)시그니처
* (위에 처럼 함수의 타입을 분리해서 정의가능)
*/
type Operation2 ={ // 함수도 객체라서 {} 쓰는것
(a:number,b:number):number;
}
// function func(a:number, b:number):void; {} 이런 형태를 톡 떼온것!
const add2: Operation2 = (a, b)=> a + b;
const sub2: Operation2 = (a,b) => a=b;
const multiply2:Operation2 = (a,b) => a* b;
const divide2: Operation2 = (a,b) => a / b;
2. 함수 타입의 호환성
함수 타입의 호환성이란 특정 함수 타입을 다른 함수 타입으로 괜찮은지 판단하는 것을 의미합니다.
다음 2가지 기준으로 함수 타입의 호환성을 판단하게 됩니다.
두 함수의 반환값 타입이 호환되는가?
두 함수의 매개변수의 타입이 호환되는가?
첫번째 기준부터 차례대로 살펴보겠습니다.
/**
* 함수 타입의 호환성
* 기본타입, 객체타입 호환성과 마찬가지로
* 특정함수 타입을 다른 함수 타입으로 취급해도 괜찮은가를 판단
* 1.반환값(리턴문)의 타입이 호환되는가
* 2.매개변수의 타입이 호환되는가
*/
//기준1. 반환값이 호환되는가
//특이하게! 매개변수 기준으로 타입호환을 판단하려고 하면, 업케스팅은 불가
type A = () => number;
type B = () => 10;
let a:A = () => 10; //number 타입
let b:B = () => 10; //number literal 타입
a = b
b = a //오류, 'number' 형식은 '10' 형식에 할당할 수 없습니다. (다운캐스팅, 오류)
//기준2. 매개변수가 호환되는가
//2-1. 매개변수의 개수가 같을때
type C = (value: number) => void;
type D = (value: 10) => void;
let c:C = (value) => {};
let d:D = (value) => {};
c = d // 오류, 업캐스팅인데 왜 오류가? 매개변수를 기준으로 하면 업캐스팅 불가,
d = c // 매개변수 기준으로 하면 다운캐스팅 가능
//매개변수가 객체 타입인 경우, 예시 보면 쉬움
type Animal = {
name: string;
};
type Dog = {
name: string;
color: string;
};
let animalFunc = (animal: Animal) => {
console.log(animal.name)
};
let dogFunc = (dog: Dog) => {
console.log(dog.name);
console.log(dog.color);
};
animalFunc = dogFunc //(dog: Dog) => void' 형식은 '(animal: Animal) => void' 형식에 할당할 수 없습니다.
//animalFunc의 매개변수에 dogFunc의 {} 안의 값을 출력
let testFunc = (animal: Animal) =>{
console.log(animal.name);
console.log(animal.color); //오류,Animal' 형식에 'color' 속성이 없습니다.
}
dogFunc = animalFunc
//dogFunc의 매개변수에 animalFunc 의 {} 안의 값을 출력
let testFunc2 = (dog: Dog) => {
console.log(dog.name)
}
//2-2. 매개변수의 개수가 다를때
type Func1 = (a:number,b:number) => void;
type Func2 = (a:number) => void;
let func1:Func1 = (a,b) =>{};
let func2:Func2 = (a) =>{};
func1 = func2;
func2 = func1; //오류, 매개변수 기준으로 (a)에 (a,b)가 있다는 조건 만족 X
3. 함수 오버로딩
함수 오버로딩이란 하나의 함수를 매개변수의 개수나 타입에 따라 다르게 동작하도록 만드는 문법입니다.
/**
* 함수의 오버로딩 (오직 타입스크립트에서만, 자스는 안됨)
* 하나의 함수를 매개변수의 개수나 타입에 따라
* 여러가지 방법으로 정의하는 방법
*/
/**
* 하나의 함수 func를 만들것임
* 모든 매개변수의 타입은 number
* Ver1. 매개변수가 1개 -> 이 매개변수에 20을 곱한값을 출력
* Ver2. 매개변수가 3개 -> 이 매개변수들을 다 더한 값을 출력
*/
//매개변수 버전들 -> 오버로드 시그니쳐
function func(a:number):void; // 만약, 실제 구현부에서 function func(a:number, b:number, c:number){} 이렇게 쓰면, 이 오버로드 시그니처는 해당 구현 시그니처와 호환되지 않습//오류, 함수 구현이 없거나 선언 바로 다음에 나오지 않습니다.
function func(a:number, b:number, c:number):void; //만약 실제 구현부를안쓰면 오류, 함수 구현이 없거나 선언 바로 다음에 나오지 않습니다.
//실제 구현부
function func(a:number, b?:number, c?:number){
if(typeof b === "number" && typeof c === "number"){
console.log(a+b+c);
}else{
console.log(a*20);
}
}
//호출해보면
func() //오류, 매개변수 버전들과 맞지 않음
func(1);
func(1,2); //오류, 매개변수 버전들과 맞지 않음
func(1,2,3);
4. 사용자 정의 타입가드
사용자 정의 타입가드란 참 또는 거짓을 반환하는 함수를 이용해
우리 입맛대로 타입 가드를 만들 수 있도록 도와주는 타입스크립트의 문법입니다.
/**
* 사용자 정의 타입가드
*/
type Dog ={
name: string;
isBark:boolean;
}
type Cat = {
name: string;
isScratch:boolean;
}
type Animal = Dog | Cat;
//만약 서로소 유니온 타입을 쓸수 없는상황, 즉 기존 타입별칭을 손댈 수 없는 상황이라면,,,
//"isBark" in animal 이런식으로 쓰면 타입이 잘 좁혀지지 않음
// 사용자 정의 타입가드
function isDog(animal:Animal):animal is Dog{//리턴문의 animal타입은 Dog다
return (animal as Dog).isBark !== undefined;
};
function isCat(animal:Animal):animal is Cat{//리턴문의 animal타입은 Cat다
return (animal as Cat).isScratch !== undefined;
}
function warning(animal:Animal){
if(isDog(animal)){
// 강아지 타입
animal; //if문이 참이면 리턴문의 animal의 타입은 Dog 이다
}else if(isCat(animal)){
// 고양이 타입
animal; //if문이 참이면리턴문의 animal의 타입은 Cat이다
}
}
'typescript' 카테고리의 다른 글
속성이 다른 데이터들을 같은 구성으로 렌더링하기 (4) | 2023.07.23 |
---|---|
타입스크립트 이해하기 (0) | 2023.05.31 |
타입스크립트 기본2 (타입별칭, 인덱스 시그니처, Enum, Any, Unknown, Void, Never 타입) (0) | 2023.05.31 |
타입스크립트 기본(원시타입, 비원시타입, 리터럴 타입) (0) | 2023.05.31 |
타입스크립트의 점진적 타입시스템 (0) | 2023.05.31 |