[ts] 조건부 타입

조건부 타입

// T extends U ? X : Y

type IsStringType<T> = T extends string? 'yes': 'no';

type T1 = IsStringType<string>;
// type T1 = "yes"
type T2 = IsStringType<number>;
// type T2 = "no"


type T3 = IsStringType<string | number>;
// type T3 = "yes" | "no"
// 이 경우에는 string | number extends string으로 동작하지 않고(이렇게 동작한다면, type T3 = "no"이다./)
// string extends string, number extends string 각각 동작하게 된다.

type T4 = IsStringType<string> | IsStringType<number>;
// type T4 = "yes" | "no"

type Array2<T> = Array<T>
type T5 = Array2<string | number>;
// type T5 = (string | number)[]
// 이 경우에는 type T5 = string[] | number[]가 아니다.

// 일반적으로는 Union type을 사용하면, type T5 처럼 동작하는 것이 맞는데 

type T6 = number | string | never;
// type T6 = string | number
// union type에 never는 없어진다. 

type Exclude<T, U> =  T extends U? never: T;


type T7 = Exclude<1 | 3 | 5 | 7, 1 | 5 | 9>;
// type t7 = 3 | 7
// 조건부 타입에서 유니온 타입은 각각 동작 한다. 

type T8 = Exclude<string | number | (()=> void), Function>;
// type T8 = string | number


type Extract<T, U> = T extends U? T: never;

type T9 = Extract<1 | 3| 5 | 7, 1 | 5| 9>;
// type T9 = 1 | 5


type ReturnType<T> = T extends(...args: any[]) => infer R? R: any;
// T 함수의 반환 타입을 뽑아내준다.

type t1 = ReturnType<() => string>;
// type t1 = string

function f1(s: string): number {
    return s.length;
}

type t2 = ReturnType<typeof f1>;
// type t2 = number


type Unpacked<T> = T extends (infer U)[]
    ? U 
    : T extends (...args: any[]) => infer U 
    ? U 
    : T extends Promise<infer U>
    ? U
    : T;

type T11 = Unpacked<string>;
// type T11 = string
type T12 = Unpacked<string[]>;
// type T12 = string
type T13 = Unpacked<()=> string>;
// type T13 = string
type T14 = Unpacked<Promise<string>>;
// type T14 = string
type T15 = Unpacked<Promise<string>[]>;
// type T15 = Promise<string>
type T16 = Unpacked<Unpacked<Promise<string>[]>>;
// type T14 = string[]


type StringPropertyNames<T> = {
    [K in keyof T]: T[K] extends string? K : never;
}[keyof T]

interface Person {
    name: string;
    age: number;
    nation: string;
}

// step 1
type StringPropertyNames1<T> = {
    [K in keyof T]: T[K] extends string? K : never;
}
type T21 = StringPropertyNames1<Person>;
// type T21 = {
//     name: "name";
//     age: never;
//     nation: "nation";
// }


// step 2
type StringPropertyNames2<T> = {
    [K in keyof T]: T[K] extends string? K : never;
}[keyof T]

type T22 = StringPropertyNames2<Person>;
// type T22 = "name" | "nation"


type StringProperties<T> = Pick<T, StringPropertyNames<T>>;

type T23 = StringProperties<Person>;
// type T23 = {
//     name: string;
//     nation: string;
// }

type Omit<T, U extends keyof T> = Pick<T, Exclude<keyof T, U>>;
interface Person {
    name: string;
    age: number;
    nation: string;
}

type T31 = Omit<Person, 'nation'| 'age'>;
// type T31 = {
//     name: string;
// }

type Overwrite<T,U> = {[P in Exclude<keyof T, keyof U>]: T[P]} & U;

interface Person3 {
    name: string;
    age: number;
}

type T41 = Overwrite<Person, { age: string; nation: string}>;
const p:T41 = {
    name: 'pius',
    age: '23',
    nation: 'korea'
};

#타입스크립트/조건부-타입