[하루 30분 러닝 타입스크립트] 객체

✨ 객체 타입

객체 타입 선언

let poetLater: {
	born: number;
	name: string;
}

poetLater = {
	born: 1935,
	name: 'Mary Oliver'
}

poetLater = 2 
// [ERROR] Type 'number' is not assignable to type '{ born: number; name: string; }'.

별칭 객체 타입

type 키워드를 사용하여 객체 별칭을 할당해 사용할 수 있습니다.

대부분의 타입스크립트 프로젝트 에서는 인터페이스(interface) 키워드를 사용하는 것을 선호합니다.

type poetLater = {
	born: number;
	name: string;
}

const poetLater: poetLater = {
	born: 1935,
	name: 'Mary Oliver'
}

✨ 구조적 타이핑

타입 스크립트 타입 시스템은 구조적 타입화(structurally typed)되어 있습니다.

즉 타입을 충조가는 모든 값을 해당 타입의 값으로 사용할 수 있습니다.

반대로 자바스크립트는 덕 타입(duck type)입니다.

type first = {
    firstName: string;
}

type last = {
    lastName: string;
}

const hasBoth = {
    firstName : 'Lucille',
    lastName : 'Clifton'
}

let first: first = hasBoth; // ok
let last: last = hasBoth; // ok

사용 검사

할당하는 값에는 객체 타입의 필수 속성이 있어야 합니다.\

일치하지 않는 타입도 허용하지 않습니다.

type name = {
    firstName: string;
    lastName: string;
}

const hasBoth: name = {
    firstName : 'Lucille',
    lastName : 'Clifton'
} // ok

const hasOnlyOne: name = {
    firstName : 'Sappho',
    // [ERROR] Property 'lastName' is missing in type '{ firstName: string; }' but required in type 'name'.
}

const hasNumber: name = {
    firstName : 'Lucille',
    lastName : 12
    // [ERROR] Type 'number' is not assignable to type 'string'
}

초과 속성 검사

초깃값에 객체 타입에서 정의된 것보다 많은 필드가 있다면 오류가 발생합니다.

객체 타입으로 선언된 위치에서 생성되는 객체 리터럴에 대해서만 일어납니다.

즉 구조적 타입이 일치한다면 타입 오류가 나지 않습니다.

type name = {
    firstName: string;
    lastName: string;
}

const hasBoth: name = {
    firstName : 'Lucille',
    lastName : 'Clifton',
    age: 12
    // [ERROR] Object literal may only specify known properties, and 'age' does not exist in type 'name'.
}

const structural = {
    firstName : 'Lucille',
    lastName : 'Clifton',
    age: 12
}

// 구조적 타입이 name과 일치하기 때문에 오류가 나지 않는다.
const structural2 : name = structural // OK

중첩된 객체 타입

type Poem = {
    title: string;
    author: {
        firstName: string;
        lastName: string;
    }
}

const poem: Poem = {
    title: 'Lady Lazarus',
    author : {
        firstName: 'Sylvia',
        lastName: 'Plath'
    }
}

자체 별칭 객체 타입으로 추출하여 가독성을 높힐 수 있습니다.

type Name = {
    firstName: string;
    lastName: string;
}

type Poem = {
    title: string;
    author: Name;
}

const poem: Poem = {
    title: 'Lady Lazarus',
    author : {
        firstName: 'Sylvia',
        lastName: 'Plath'
    }
}

선택적 속성

?: 를 이용하여 선택적 속성을 나타낼 수 있습니다.

type Poem = {
    title?: string;
    author: string;
}

// 위는 아래와 같다.
type Poem = {
    title: string | undefined;
    author: string;
}

✨객체 타입 유니언

유추된 객체 타입 유니언

조건적으로 여러 타입을 가질 수 있는 값이 주어지면, 타입스크립트는 객체 타입 유니언을 유추합니다

const poem = Math.random() > 0.5 
	? {name: "Image", pages: 7} 
	: {name: "Kind", rhymes: true}

/*
const poem: {
    name: string;
    pages: number;
    rhymes?: undefined;
} | {
    name: string;
    rhymes: boolean;
    pages?: undefined;
}
 */

명시된 객체 타입 유니언

잠재적으로 존재하지 않을 수 있는 속성의 접근을 제한하여 코드의 안전을 지킬 수 있습니다.

type PoemWithPages = {
    name: string;
    pages: number;
}

type PoemWithRhymes = {
    name: string;
    rhymes: boolean;
}

type Poem = PoemWithPages | PoemWithRhymes

const poem: Poem = Math.random() > 0.5 
	? {name: "Image", pages: 7} 
	: {name: "Kind", rhymes: true}

poem.pages // [ERROR] Property 'pages' does not exist on type 'Poem'.
poem.rhymes // [ERROR] Property 'rhymes' does not exist on type 'Poem'.

객체 타입 내로잉

if문을 이용하여 타입 내로잉을 적용할 수 있습니다.

in 키워드를 사용해야 합니다.`

if(poem.pages){
	// [ERROR] Property 'pages' does not exist on type 'Poem'.
	 ...
} 

//OK
if('pages' in poem){
	poem.pages
}
if('rhymes' in poem){
	poem.rhymes
}

판별된 유니언

판별된 유니언 쓸모없어 보이지만 이후 제네릭의 데이터 운영을 위해 사용됩니다.

type PoemWithPages = {
    name: string;
    pages: number;
    type: 'pages'
}

type PoemWithRhymes = {
    name: string;
    rhymes: boolean;
    type: 'rhymes'
}

type Poem = PoemWithPages | PoemWithRhymes

const poem: Poem = Math.random() > 0.5 
    ? {name: "Image", pages: 7, type: "pages"} 
    : {name: "Kind", rhymes: true, type: "rhymes"}

if(poem.type === 'pages'){
    poem.pages
}

✨교차 타입

& 교차타입을 사용해 여러 타입을 동시에 나타냅니다.

type PoemWithPages = {
    name: string;
    pages: number;
}

type PoemWithRhymes = {
    name: string;
    rhymes: boolean;
}

type Poem = { name: string } & ({ pages: number } | { rhymes: boolean }) 

const poem: Poem = { name: "Image", pages: 7 } 
const poem2: Poem = { name: "Kind", rhymes: true }

교차 타입의 위험성

스스로나 타입스스립트의 컴파일러를 혼동시키는 방법이므로 간결성을 유지하는 것이 중요합니다.

간결성을 지키지 않을 경우 긴 할당 가능성 오류가 생길 수 있습니다.

never

원시 값은 동시에 여러 타입이 될 수 없습니다

type Impossible = number & string;
// type Impossible = never