과거 프로그래밍 자료들/Javascript&typescript

[TS] 공변성, 반공변성, 오버로딩

평부 2022. 9. 18. 14:13

출처 : https://github.com/ZeroCho/ts-all-in-one

 

GitHub - ZeroCho/ts-all-in-one

Contribute to ZeroCho/ts-all-in-one development by creating an account on GitHub.

github.com

 

* 공변성, 반공변성, 이변성, 불변성

▶ 함수 간에 서로 대입할 수 있냐, 없냐 여부

 

* 리턴값은 더 넓은 타입이면 대입 가능

* 매개변수더 좁은 타입이면 대입 가능

 

//해당 코드는 가능
function a(x: string | number): number {
    return +x;
}

a('1'); //1

type B = (x: string) => string | number;
const b: B = a;

 

 

 

* 리턴값

//리턴값 예시
function a(x: string): number {
    return +x;
}

a('1'); //1

type B = (x: string) => number | string;
const b: B = a;

//a는 string 받아서 number 리턴
//B는 string 받아서 number 또는 string 리턴
//서로 타입이 다름 허나 대입이 됨 => ?


//오류 나는 경우
function a(x: string): number | string {//(x: string) => string 또는 (x: string) => number 가능
    return +x;
}

a('1'); //1

type B = (x: string) => number; //(x: string) => string도 되는데 type B에는 불가능
const b: B = a;

 

 

 

* 매개변수

//매개변수
function a(x: string | number): number {
    return +x;
}

a('1'); //1

type B = (x: string) => number;
const b: B = a;

//매개변수는 string | number을 하나로 보고 좁은 타입으로 대입 가능(리턴값이랑 반대)
//오히려 넓은 타입으로는 대입 불가


//오류 나는 경우
function a(x: string): number {
    return +x;
}

a('1'); //1

type B = (x: string | number) => number;
const b: B = a;

 

 

* 타입 넓히기, 타입가드 

//타입 넓히기
//TS가 모든 상황을 고려해서 타입을 넓힘
let A = 5;

let a: string | number = 5

//타입가드 : 타입 좁히기
if (typeof a === "string") {
    console.log("이건 문자열",a)
} else if (typeof a === "number") {
    console.log("이건 숫자", a)
}

 

 

* 오버로딩

▶ 같은 타입을 여러 번 선언

▶ 여러 가진 상황 중 한 가지에 해당하는 것을 만들기 위함

 

 

 

[예시] - filter의 경우 방식 2가지 있음

filter<S extends T>(predicate: (value: T, index: number, array: readonly T[]) => value is S, thisArg?: any): S[];
혹은
filter(predicate: (value: T, index: number, array: readonly T[]) => unknown, thisArg?: any): T[]; 
둘 다 사용 가능

 

 

* 오버로딩 예시 1

//declare : 함수 선언만 하고 실제 코드는 다른 곳에 위치
declare function add(x: number, y: number): number
declare function add(x: number, y: number, z: number): number

add(1, 2);
add(2, 3, 4);

//한 방에 타이핑 하고 싶을 때
//(위의 코드와 같은 내용) 그럴 때 옵셔널 사용
declare function add(x: number, y: number, z?: number): number

add(1, 2);
add(2, 3, 4);


//오버로딩은 모든 케이스가 다 되도록 -> 여러 개 중 하나에 걸리게 함
declare function add(x: number, y: number): number
declare function add(x: number, y: number, z: number): number
declare function add(x: string, y: string): string

add(1, 2);
add(2, 3, 4);
add('1', '2');

 

 

* 오버로딩 예시 2 

▶ 인터페이스, 클래스 안에서도 오버로딩 가능

//interface
interface Add {
    (x: number, y: number): number;
    (x: string, y: string): string;
}
//오버로딩 하면 실제 구현부에서는 any 사용 가능
const add: Add = (x: any, y: any) => x + y;


//class
class A {
    add (x: number, y: number): number;
    add (x: string, y: string): string;
    //위의 두 add만 오버로딩, 아래 any는 무시됨
    add(x: any, y: any) {
        return x + y;
    }
}

//const c: number
const c = new A().add(1, 2); //숫자면 add (x: number, y: number): number;
//const C: string
const C = new A().add('1', '2'); //문자면 add (x: string, y: string): string;