개발/typescript

타입스크립트 기초 문법 - 함수 타입과 호환성

모그 2023. 12. 27. 11:23

1. 함수에서의 타입 정의

보통의 함수에는 매개변수와 반환값이 존재한다.

반환값은 타입을 설정하지 않아도 자동으로 추론되지만

매개변수는 타입을 꼭 설정해줘야한다.

✔️화살표함수도 마찬가지

function foo(a:number,b:number){
	return a+b;
}

const foo = (a:number,b:number) => a+b;

 

타입 별칭에서도 선택적 프로퍼티를 사용할 수 있듯이 함수의 매개변수도 선택적으로 사용할 수 있다.

 

function foo(name:string, age?:number){
...
}

 

하지만 이 경우 선택적 매개변수는 지정된 타입 혹은 undefined로 추측되기때문에 타입좁히기가 필요하다.

 

function foo(name:string, age?:number){
    if(typeof age === "number"){
    	실행문
    }
}

 

선택적 매개변수는 반드시 모든 변수의 맨 뒤에 와야한다.

 

  • ...rest 매개변수

여러 숫자를 하나의 배열로 묶어주는 역할

때문에 ...rest의 타입을 정의할 땐 number[]로 정의한다.

 

function foo(...rest:number[]){
	실행문
}

 

결국 배열의 형태이기때문에 튜플 타입으로 설정해도 무방하다.

function foo(...rest:[number,number]){
	실행문
}

다만 이렇게 되면
foo(123,10) //정상
foo(12,5,90) //오류

 

 

 

함수의 타입을 정의하는 방법은 크게 두 가지가 있다.

2.함수 타입 표현식

객체에서 자주 써먹었던 타입 별칭을 이용한 방법을 함수에서도 쓸 수 있다.

type Add = (a:number, b:number) => number;

const add:Add = (a,b) => a+b;

 

함수의 선언&구현 부분과 타입을 분리할 수 있어 훨씬 읽기 깔끔한 코드가 된다.

그리고 반환값이 다른 여러 개의 함수가 동일한 타입을 갖고있을 때도 깔끔하게 코드 정리 가능(아래 예시)

 

type Add = (a:number, b:number) => number;

const add:Add = (a,b) => a+b;
const sub:Add = (a,b) => a-b;
const mul:Add = (a,b) => a * b;

 

3.호출 시그니쳐

객체에서의 타입별칭 형식처럼 정의하는 방법이다.

type Func = {
	(a:number, b:number) : number; 
}

이런식

 

4. 함수의 호환성

4-1. 반환값 타입에 따라

기본 타입의 호환성을 따졌을 때 처럼 a =b 일 때 반환값 a가 b의 슈퍼타입일 때 가능하다.

type A = () => number;
type B = () => 100;

let a:A = () => 100;
let b:B = () => 100;

a = b // 가능
b = a // 오류

 

함수 a의 반환값 타입은 number

함수 b의 반환값 타입은 number 리터럴타입으로 a함수타입이 b함수타입의 슈퍼타입

a=b의 관계에서 a가 b의 슈퍼타입이어야한다는 점을 생각하면 당연한 원리이다.

 

4-2. 매개변수의 타입에 따라

  • 매개변수의 개수가 같을 때

하지만 조금 다르게 생각해야 하는 경우가 있다.

type A = (val: number) => void;
type B = (val: 10) => void;

let a:A = (val) => {};
let b:B = (val) => {};

이 경우
b = a // 서브 = 슈퍼 관계일 때 호환된다.

 

왜냐하면

매개변수 타입이 객체 타입일 때를 예로 들어 생각해볼 수 있다.

type A = {
    name:string;
}

type B = {
    name=string;
    age:number
}

let a = (value:A) => {
 console.log(value.name)
}

let b = (value2:B) {
 console.log(value.name)
 console.log(value. age)
}

a = b 결과

let a = (value:A) => {
 console.log(value.name);
 console.log(value.age)
}

매개변수 타입은 A를 따르고 있지만 함수 실행문 부분에서는 age라는 타입 B의 프로퍼티에도 접근하고있기기에 오류가 발생한다.

 

반대로 

b=a 결과
let b = (value2:B) => {
	console.log(value2.name);
}

 

으로 정상적으로 name 프로퍼티에 접근한다.

 

  • 매개변수의 개수가 다를 때 
type A = (a:number; b:number) => void;
type B = (a:number) => void;

이런 경우

let a:A = (a,b) => {};
let b:B = (a) => {};

a = b //일 때 호환된다.