객체의 메서드 타입을 정의하는 상황은 종종 발생한다.

객체의 메서드 타입을 정의하는 방법은 2가지가 있다.

두 방법은 얼핏 비슷해 보이지만 미묘한 차이를 가지고 있다.

interface Props<T extends string> {
    onChangeA?: (selected: T) => void;
    onChangeB?(selected: T): void;
}

const Component = () => {
    const changeToPineApple = (selectedApple: "apple") => {
        console.log("this is pine" + selectedApple);
    }

    return (
        <Select
            // Error
            // onChangeA={changeToPineApple}
            // OK
            onChangeB={changeToPineApple}
        />
    )
}

(— strict 모드에서) 부모 컴포넌트에서 매개변수가 apple일 때 실행되는 메서드를 생성했다 가정

on-ChangeA일 때는 타입 에러 발생, onChangeB일 때는 타입에러 발생 X

// 모든 유저(회원, 비회원)은 id를 갖고 있음
interface User {
    id: string;
}

interface Member extends User {
    nickName: string;
}

let users: Array<User> = [];
let members: Array<Member> = [];

users = members; // OK
members = users; // Error

모든 User가 id를 가지고 있으며 회원(Member)은 회원 가입 시 등록한 별명(nickName)을 추가로 갖고 있다. Member는 User를 상속하고 있는데 User보다 더 좁은 타입이자 User의 서브타입이다.

타입 A가 B의 서브타입일 때, T<A>가 T<B>의 서브타입이 된다면 공변성을 띠고 있다고 말한다.


// 모든 유저(회원, 비회원)은 id를 갖고 있음
interface User {
    id: string;
}

interface Member extends User {
    nickName: string;
}

type PrintUserInfo<U extends User> = (user:U) => void;

let printUser: PrintUserInfo<User> = (user) => console.log(user.id);

let printMember: PrintUserInfo<Member> = (user) => console.log(user.id, user.nickName);

printMember = printUser; //OK

printUser = printMember; // Error - Property 'nickName' is missing in type 'User'
// but required in type 'Member'