04 객체

개발공부·2023년 3월 25일
0

타입스크립트

목록 보기
7/8
post-thumbnail

1. 객체 타입

  • {…} 구문을 사용해 객체 리터럴 생성 시, 타입스크립트는 해당 속성을 기반으로 새로운 객체 타입 또는 타입 형태를 고려함

→ 값의 속성에 접근하려면 value.멤버 또는 value[’멤버’] 구문 사용

const pet = {
	born: 2008,
	name: "ari"
}

pet['born']; //타입 number
pet.name //타입 string

// pet.end;
//Property 'end' does not exist on type '{ born: number; name: string; }'

* 객테 타입의 선언

→ 명시적 선언
→ 객체 리터럴과 유사해보이나 필드 값 대신 타입 사용

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

pets = {
    born: 2008,
    name: "ari"
}

// pets = "ari";
//Type 'string' is not assignable to type '{ born: number; name: string; }'

* 별칭 객체 타입
→ 타입스크립트의 타입 시스템을 배울 때, 타입스크립트가 객체 리터럴을 해석하는 방법을 이해하는 것은 매우 중요함

type pets =  { //타입으로 작성
    born: number;
    name: string;
}

let laterPets: pets;

laterPets = {
    born: 2008,
    name: "ari"
}

// laterPets = "ari";
//Type 'string' is not assignable to type 'pets'

2. 구조적 타이핑

* 구조적 타이핑

→ 구조적으로 타입화 : 타입을 충족하는 모든 값을 해당 타입의 값으로 사용 가능
(덕 타이핑(오리처럼 보이고 오리처럼 꽥꽥이면 오리일 것과는 다름)
→ 자바스크립트는 덕 타입, 타입스크립트는 구조적으로 타입화

type WithFirstName = {
    firstName: string;
}

type WithLastName = {
    lastName: string;
}

const hasBoth = {
    firstName: "백호",
    lastName: "강",
}

let withFirstName: WithFirstName = hasBoth;
let withLastName: WithLastName = hasBoth;

* 사용 검사

→ 객체 타입으로 애너테이션 위치에 값을 제공할 때 타입스크립트는 값을 해당 객체 타입에 할당 할 수 있는지 확인
→ 할당하는 값에는 객체 타입의 필수 속성이 있어야 함

type FisrtAndLstNames = {
    first: string;
    last: string;
}

const hasBoth: FisrtAndLstNames = {
    first: "백호",
    last: "강"
}

const hasOnlyOne: FisrtAndLstNames = {
    first: "태웅"
    //Property 'last' is missing in type '{ first: string; }' but required in type 'FisrtAndLstNames'.
}
type TimeRange = {
	start: Date;
}

const hasStartString: TimeRange = {
	start: "1996-01-31"; //오류 type은 Date로 명시하나 실제 값은 string
}

* 초과 속성 검사

→ 변수가 객체 타입으로 선언, 초기값에 정의된 것보다 많은 필드 존재 시 오류 발생
→ 변수를 객체타입으로 선언하는 것 : 타입 검사기가 해당 타입에 예상되는 필드만 있는지 확인

type pets =  { //타입으로 작성
    born: number;
    name: string;
}

const petMatch: pets = {
    born: 2008,
    name: "ari"
}

const extraPet: pets = { //오류 발생
    activity: "walking",
    //Type '{ activity: string; born: number; name: string; }' is not assignable to type 'pets'.
    //Object literal may only specify known properties, and 'activity' does not exist in type 'pets'
    born: 2008,
    name: "ari"
}

const existingObject = {//오류 없음
    activity: "walking",
    born: 2008,
    name: "ari"
}

const extraPropertyButOk: Pets = existingObject;
//초기값이 구조적으로 Pets와 일치하기 때문

* 중첩된 객체 타입

→ 중첩된 객체 타입을 고유한 타입 이름으로 바꿔서 사용 시 코드와 오류 메시지를 더 읽기 쉬워짐

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

const poemMatch: Poem = {
    author: {
        firstName: "소월",
        lastName: "김",
    },
    name: "한용운"
};

const poemMismatch: Poem = {
    author: {
        name: "김소월",
        //Type '{ name: string; }' is not assignable to type '{ firstName: string; lastName: string; }'.
        //Object literal may only specify known properties, and 'name' does not exist in type '{ firstName: string; lastName: string; }'
    }
    name: "진달래"
}

* 선택적 속성

→ 모든 객체에 객체 타입 속성이 필요한 것은 아님
→ 타입의 속성 애너테이션에서 앞에 ? 추가

type Book = {
    author?: string;
    pages?: number;
}

const ok: Book = {
    author: "김소월",
    pages: 80,
}

const missing: Book = {
    author: "김소월"
    //pages가 없어도 오류 없음
}

3. 객체 타입 유니언

* 속성이 조금 다른, 하나 이상의 서로 다른 객체 타입이 될수 있는 타입 설명할 수 있어야 함

* 유추된 객체 타입 유니언
→ 변수에 여러 객체 타입 중 하나가 될 수 있는 초기값이 주어지면 타입스크립트는 해당 타입을 객체 타입 유니언으로 유추

const poem = Math.random() > 0.5 
    ? { name : "윌리엄 셰익스피어", pages: 500 }
    : { name : "조지 오웰", rhymes: true }

//타입
// {
//     name: string;
//     pages: number;
//     rhymes?: undefined; 
// }

// {
//     name: string;
//     pages: number;
//     rhymes?: boolean;
// }

// {
//     name: string;
//     pages: number;
//     rhymes?: booleans | undefined;
// }

* 명시된 객체 타입 유니언

→ 값의 타입이 객체 타입으로 구성된 유니언이라면 모든 유니언 타입에 존재하는 속성에 대한 접근만 허용됨
→ 속성 name에 접근하는 것은 name속석이 항상 존재하기 때문에 허용되나 pages와 ryhmes는 항상 존재한다는 보장이 없음
→ 리터럴 타입이나 원시 타입 모두, 혹은 둘 중 하나로 이루어진 유니언 타입에서 모든 타입에 존재하지 않은 속성에 접근 시 타입을 좁혀야 하는 것처럼 객체 타입 유니언도 타입을 좁혀야 함

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

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

type Poem = PoemWithPages | PoemWithRhymes;

const poem: Poem = Math.random() > 0.5
    ? { name : "윌리엄 셰익스피어", pages: 500 }
    : { name : "조지 오웰", rhymes: true };

console.log(poem.name);
//"The Double Image"
//"Her Kind"

console.log(poem.pages) //오류
//Property 'pages' does not exist on type 'Poem'

* 객체 타입 내로잉
→ 코드에서 객체의 형태를 확인하고 타입 내로잉이 객체에 적용됨

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

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

type Poem = PoemWithPages | PoemWithRhymes;

const poem: Poem = Math.random() > 0.5
    ? { name : "윌리엄 셰익스피어", pages: 500 }
    : { name : "조지 오웰", rhymes: true };

console.log(poem.name);

if("pages" in poem) {
    poem.pages; //poem은 PoemWithPages로 좁혀짐
} else {
    poem.rhymes; //poem은 PoemWithRhymes로 좁혀짐
}

* 판별된 유니언

→ 유니언 타입으로 된 객체의 또 다른 인기 있는 형태 = 객체의 속성이 객체의 형태를 나타나도록 함
→ 타입 형태 : 판별된 유니언, 객체의 타입을 가리키는 속성 : 판별

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 : "윌리엄 셰익스피어", pages: 500, type: "pages" }
    : { name : "조지 오웰", rhymes: true, type: 'rhymes' };

if(poem.type === "pages") {
    console.log(`영국 작가의 페이지: ${poem.pages}`)
} else {
    console.log(`It's rhymes: ${poem.rhymes}`)
}

poem.type; //type: "pages" | "rhymes"

poem.pages;
//Property 'pages' does not exist on type 'Poem'.
//  Property 'pages' does not exist on type 'PoemWithRhymes'.

4. 교차 타입 타입

* 유니언 타입 : 둘 이상의 다른 타입 중 하나의 타입이 될 수 있음 나타냄

자바스크립트 : | , 타입스크립트 & 교차 타입
→ 교차 타입은 유니언 타입과 결합 가능, 하나의 타입으로 판별된 유니언 타입 설명 시 유용

type Artwork = {
    genre: string;
    name: string;
}

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

type WrittenArt = Artwork & Writing;
// {
//     genre: string;
//     name: string;
//     pages: number
// }
type ShortPoem = { author: string } & (
    | { name : string; type : 'drama';}
    | { meter: number; type: 'movie' }
)

const moringGlory: ShortPoem = {
    author : "김은숙",
    name: "The Glory",
    type: 'drama'
}

const oneArt: ShortPoem = {
    //Type '{ author: string; type: "movie"; }' is not assignable to type 'ShortPoem'.
    //Type '{ author: string; type: "movie"; }' is not assignable to type '{ author: string; } & { meter: number; type: "movie"; }'.
    author: "이노우에 다케히코,
    type: "movie"
}

* 교차 타입의 위험성

→ 타입스크립트 컴파일러를 혼동시키는 방식으로 사용하기 쉬움
→ 가능한 간결하게 코드 유지

type ShortPoemBase = { author : string };
type Haiku = ShortPoemBase & { name : string; type: "drama" };
type Villanella = ShortPoemBase & { meter: number; type: "movie" };
type ShortPoem = drama | movie;

const oneArt: ShortPoem = {
    //Type '{ author: string; type: "movie"; }' is not assignable to type 'ShortPoem'.
    //Type '{ author: string; type: "movie"; }' is not assignable to type 'Villanella'.
    author: "이노우에 다케히코",
    type: "movie"
}

* never

→ 교차 타입은 잘못 사용하기 쉽고 불가능한 타입 생성
→ 두 개의 원시 타입을 함께 시도 시 never 키워드로 표시되는 never 타입됨

type NotPossible = number & string; //never
let notNumber: NotPossible = 0;
//Type 'number' is not assignable to type 'never'

let notString: never = "";
//Type 'string' is not assignable to type 'never'
profile
개발 블로그, 티스토리(https://ba-gotocode131.tistory.com/)로 갈아탐

0개의 댓글