running TSC : part1

the Other Object·2023년 4월 6일
0

ch1.

바닐라자바스크립트

  • 중요한 언어 확장이나 프레임워크 없이 자바스크립트를 사용하는 것을 말한다
  • 순수자바스크립트 vanilla
  • tsc가 자바스크립트에 있는 주요함정을 극복하기 위해 적절한 기능추가한 이유, 주요함정의 치명성
* 코드의 문서화

interface Painter {
  // Painter에 세가지 속성이 있다, 그중 2가지는 메서드이다.
  finish(): boolean;
  ownMaterials: Material[];
  paint(
    painting: string, 
    materials: Material[]
  ): boolean;
}
function paintPainting(
  painter: Painter, 
  painting: string
): boolean{ (...) }
  • 많은 자바스크립트 프로젝트는 소스코드를 실행할 수 있는 자바스크립트로 변환하기 위해서 타입스크립트의 자체 컴파일러 대신 '바벨'같은 전용변환기를 사용한다.

  • tsconfig.json 파일을 생성할 때의 또다른 이점은 편집기에서 특정 폴더를 열었을 때 편집기가 해당폴더를 타입스크립트 프로젝트로 인식한다는 것, vscode에서 폴더를 열면 타입스크립트 코ㅡ를 분석하는데 사용하는 설정은 해당 폴더의 tsconfig.json을 따르게 된다.

  • vscode는 타입스크립트를 지원하고 자체적으로 타입스크립트로 빌드된다.

타입스크립트의 제약

  • 자바스크립트 코드를 구조화하는데는 도움이 되지만 타입 안정성 강화를 제외하고는 해당 구조가 어떻게 보여야 하는지에 대해서는 어떤 강요도 없다.
  • 특정 대상만을 위한 독단적인 프로엠워크가 아님, 자바스크립트에서 사용해썬 아키텍처 패턴 중 뭐든 사용해서 코드를 작성할 수 있고, 타입스크립트가 이를 지원한다.
  • 설계목표
    (1) 현재와 미래의 ECMA스크립트 제안에 맞춘다.
    (2) 모든 자바스크립트 코드의 런타임 동작을 유지한다.
  • tsc코드는 브라우저나 node.js와 같은 환경에서 실행되기 전에 자바스크립트로 컴파일 되어야 한다. 빌드 파이프라인은 대부분 성능 저하를 무시하도록 설정된다. 코드에서 발생할 수 있는 오류를 분석하는 느린 tsc기능은 실행 가능한 애플리케이션 코드 파일 생성하는 것과는 분리된 채로 수행됨.

ch2.

타입시스템

  • 타입 : jsc에서 다루는 값의 형태에 대한 설명
  • 형태 : 값에 존재하는 속성과 메서드 그리고 내장되어있는 typeof 연산자가 설명하는 것을 의미
  • 타입시스템의 작동
    (1) 코드를 읽고 존재하는 모든 타입과 값을 이해한다
    (2) 각 값이 초기선언에서 가질 수 있는 타입을 확인한다.
    (3) 각 값이 추후 코드에서 어떻게 사용 될 수 있는지 모든 방법을 확인
    (4) 값의 사용법이 타입과 일치하지 않으면 사용자에게 오류표시

오류종류

  • 구문오류 : 타입스크립트가 자바스크립트로 변환되는 것을 차단한 경우
    - 타입스크립트가 코드로 이해할 수 없는 잘못된 구문을 감지할 때 발생
  • 타입오류 : 타입 검사기에 따라 일치하지 않는 것이 감지 된 경우
    - 타입오류가 있음에도 ㅂ루구하고 자바스크립트 코드를 ㅊㄹ력할 수 있지만, 출력 된 jsc코드가 원하는대로 실행되지않을 가능성이 있다는 신호를 타입오류로 알려준다
* 할당 가능성

let firstName = "Carole";
firstName = 'Joan';

할당가능성 : 타입스크립트에서 함수호출이나 변수에 값을 제공할 수 있는지 여부를 확인하는 것., 전달된 값이 예상된 타입으로 할당 가능한지의 여부를 확인한다.

'Type ...is not assignable to type...' 형태의 가장 일반적인 오류
- 해당 오류메시지에 언급된 첫번째 typt은 : 코드에서 변수에 할당하려고 시도하는 값이다.
- 두번째 type은 : 첫번째 타입., 값이 할당되는 변수이다.

- 변수에 타입스크립트가 읽어야 할 초기값이 없는 경우도 있다. tsc는 나중에 사용할 변수의 초기 타입을 파악하려고 시도하지 않난다. 그리고 기본적으로 변수를 암묵적인 any 타입으로 간주한다., 변수는 세상의 모든 것이 될 수 있음을 나타냄.
- 초기타입을 유추할 수 없는 변수는 `진화하는 any` 라고 부름. 특정 타입을 강제하는 대신 새로운 값이 할당 될 때마다 변수타입에 대한 이해를 발전시킨다.


// 타입: any
let rocker;
// 타입: string
rocker = "John Jett"
// Ok
rocker.toUpperCase();
// 타입: number
rocker = 19.58;
// Ok
rocker.toPrecision(1);
// Error: 'toUpperCase'does not exist on type 'number'.
rocker.toUpperCase();

tsc는 초기값을 할당하지 않고도 변수의 타입을 선언할 수 있는 구문인 타입애너테이션typeAnnotation을 제공한다. 이것은 변수 이름의 뒤에 배치되며 콜론(:)과 타입 이름을 차례대로 기재함. 

변수에 타입애너테이션으로 정의한 타입 외의 값을 할당하면 타입 오류발생한다.

* 불필요한 타입애너테이션
	- tsc가 자체적으로 수집할 수 없는 정보를 타입스크립트에 제공할 수 이싸. 타입을 즉시 유추할 수 있는ㄴ 변수에도 애너테이션을 사용할 수 있다.
    
    let firstName: string = "Tina";

- 아무것도 변하지않는 변수에는 타임에너ㅔ이션을 ㅊ가하지않는것을 선호한다.
- 코드를 명확하게 문서화하거나 실수로 변수타입이 변경되지 않도록 타입스크립트를 보호하기 위해 변수에 명시적으로 타입애너테이션을 포함하는 것이 경우에 따라서는 유용할 수 있다. 

- 타입스크립트는 변수에 할당 된 값이 원래 타입과 일치하는지 확인하는 것 이상을 수행


import {value} from './values';
export const doubled = value * 2;

scope : 변수에 접근할 수 있는 범위
모듈 : export 또는 import가 있는 파일
스크립트 : 모듈이 아닌 모든 파일

- 파일이 스크립트면 타입스크립트는 해당 파일을 전역 스코프로 간주하므로 모든 스크립트가 파일의 내용에 접근가능., 스크립트 파일에 선언 된 변수는 다른 스크립트 파일에 선언된 변수와 동일한 이름을 가질 수 없다.

- 타입스크립트 파일에 Cannot redeclare... 라는 오류 : 파일에 아직 export 또는 import 문을 추가하지 않았기 때문일 수 있다. ECMA스크립트 사양에 따라 export 또는 import 문 없이 파일을 모듈로 만들어야 한다면 파일 아무곳에나 export{};를 추가해서 강제로 모듈이 되도록 만들며 ㄴ됨.

ch3.

상수를 제외한 모든 것은 변한다.
시간이 지나면서 값도 변할 수 있다.

  • tsc가 해당 값을 바탕으로 추론을 수행하는 두가지 핵심개념
    (1) 유니언union : 값에 허용 된 타입을 두개 이상의 가능한 타입으로 확장하는 것
    (2) 내로잉narrowing : 값에 허용 된 타입이 하나 이상의 가능한 타입이 되지 않도록 좁히는 것
1. 유니언타입

let mathematician = Math.random() > 0.5 ? undefined : "Mark Goldberg";

- mathematician은 어떤 타입??
  - 둘 다 잠재적 타입이긴 하지만 무조건 undefined거나 혹은 무조건 string도 아니다. mathematician은 undefined 아거나 string 일 수 있다. '이거 혹은 저거' 와 같은 타입을 말한다. 

let mathmatician: string | undefined

let thinker: string | null = null;
if (Math.random() > 0.5) {
  thinker = "Susanne Langer";
}

- 유니언타입 선언의 순서는 중요하지 않다.
- 모든 유니언 타입에 존쟇지 안ㅇㅎ는 속성에 대한 접근을 제한하는 것은 안전조치에 해당한다.
- 유니언타입으로 정의된 여러 타입 중 하나의 타입으로 된 값의 속성을 사용하려면 코드에서 값이 보다 구체적인 타입 중 하나라는 것을 tsc에 알려야 한다. 이러한 과정을 : 내로잉


2. 내로잉

- 값이 정의,선언 혹은 이전에 유추 된 것보다 더 구체적인 타입임을 코드에서 유추하는 것이다. 
- tsc가 값의 타입이 이전에 알려진 거솝다 더 좁혀졌다는 것을 알게 되면 값을 더 구체적인 타입으로 취급한다. 타입을 좁히는데 사용할 수 있는 노리적 검사를 `타입가드` 라고 한다. 


- typeof 연산자를 사용한 내로잉
let researcher = Math.random() > 0.5 ? "Rosalind Frankie" : 51;
if (typeof researcher === 'string') {
  researcher.toUpperCase();
}
* 리터럴 타입

- philosopher 변수를 보자
const philosopher = "Hypatia";
- philosopher 의 타입은 ?
  String타입이다.
  philosopher 는 원시타입 값 중 어떤 것이 아닌 특정 원시값으로 알려진 타입. 이것이 리터럴 타입
- 원시타입 string 은 존재할 수 있는 모든 가능한 문자열의 집합을 나타내지만, 리터럴 타입인 "Hypatia"는 하나의 문자열만 나타냄
- 변수를 const 로 선언하고 직접 리터럴 값을 할당하면 tsc는 해당 변수를 할당 된 리터럴 값으로 유추한다.
- 각 원시타입은 해당 타입이 가질 수 있는 가능한 모든 리터럴 값의 전체 조합으로 생각할 수 있다., 원시타입은 해당 타입의 가능한 모든 리터럴 값의 집합이다.


const lifespan: number | "ongoing" | "uncertain";

lifespan = 89;
lifespan = "ongoing";
lifespan = true;


// Error : Type 'true' is not assignable to type ' number|"ongoing"|"uncertain" '
* 리터럴 할당 가능성

const specificallyAda: "Ada";

specificallyAda = "Ada";
// Error: Type '"Byron"' is not assignable to type '"Ada"'.
specificallyAda = "Byron";

// 타입: string
const someString = "";
// Error : Type 'string' is not assignable to type 'Ada'
specificallyAda = someString;


01처럼 동일한 원시타입이어도 서로 다른 리터럴 타입은 서로 할당 할 수 없다.
specificallyAda 는 리터럴타입 Ada 로 선언했으므로 값에 Ada를 할당할 수 있지만,
Byron 이나 string 타입 값은 할당할 수 없다.
그러나 리터럴 타입은 그 값이 해당하는 원시 타입에 할당할 수 있다. 
* null검사
- '잠재적으로 정의되지않은 undefined 값'
- 다른 타입이 필요한 위치에서 null값을 사용하도록 허용하는 많은 타입시스템을 가리키는 용어
- 엄격한 null검사를 활성화해야만 코드가 null 또는 undefined 값으로 인한 오류로부터 안전한지 여부를 쉽게 파악할 수 있다.

* 참 검사를 통한 내로잉
	- jsc에서 참 또는 truthy(boolean문맥에서 참으로 평가되는것)&& 연산자 또는 if 문처럼 boolean 문맥에서 true로 간주된다.
    - jsc에서 false, 0, -0, 0n, "", null, undefined, NaN 처럼 falsy 로 정의된 값을 제외한 모든 값은 참이다.
    - tsc는 잠재적인 값 중 truthy로 확인 된 일부에 한해서만 변수의 타입을 좁힐 수 있다. 
    
let geneticist = Math.random() > 0.5 ? "Barbara McClintock" : undefined;

- geneticist 는 string|undefined 타입이며, undefined 는 항상 falsy 이므로 tsc는 if 문의 코드블록에서는 geneticist 가 string 타입이 되어야 한다고 추론가능.

* 초기값이 없는 변수
- jsc에서 초기값이 업ㅇㅅ는 변수는 기본적으로 undefined 가 된다. 만약 undefined를 포함하지 않는 타입으로 변수를 선언한 다음, 값을 할당하기 전에 사용하려고 시도한다면 다음과 같은 오류메시지가 나타난다.

const mathematician: string;
mathematician?.length;
//Error: Variable 'mathematician' is used before being assigned
* 타입스크립트에는 재사용하는 타입에 더 쉬운 이름을 할당하는 타입별칭이 있다. 
* 타입별칭은 : type 새로운이름 = 타입  의 형태를 갖는다.

type MyName = ...;

타입 별칭은 자바스크립트가 아니다. 런타임 코드에서는 참조할 수 없다. 타입스크립트는 런타임에 존재하지 않는 항목에 접근하려고 하면 타입 오류로 알려준다.

type SomeType = string | undefined;
console.log(SomeType);
//Error: 'SomeType' only refers to a type, but is being used a value here.


* 타입별칭은 다른 타입 별칭 참조가 가능하다.
* 유니언 타입인 타입 별칭 내에 또다른 유니언 타입인 타입 별칭을 포함하고 있다면 다른 타입 별칭을 참조하는 것이 좋다.

type Id = number | string;
type IdMaybe = Id | undefined | null;
// IdMaybe 타입은 다음과 같음. number | string | undefined | null

ch.4

  • 객체 리터럴은 각자의 타입이 있는 키와 값의 집합이다.
    복잡한 객체형태를 설명하는 방법과 타입스크립트가 객체의 할당가능성을 확인하는방법에 대해 .
  • 객체타입
  • {...}구문을 사용해서 객체 리터럴을 생성하면 타입스크립트는 해당 속성을 기반으로 새로운 객체 타입 또는 타입형태를 고려한다.

  • 해당 객체타입은 객체의 값과 동일한 속성명과 원시 타입을 갖는다.

  • 값의 속성에 접근하려면 value.멤버 또는 value['멤버'] 구문을 사용한다.

  • 다음 poet 변수의 타입은 number 타입인 born 과 string 타입인 name 으로 이루어진 두개의 속성을 갖는 객체이다. 이 두개의 속성에 접근하는 것은 허용되지만, 다른 속성 이름으로 접근하려고 하면 해당 이름이 존재하지 않는다는 타입오류가 발생한다.

const poet = {
  born: 1935,
  name: "Mary Oliver"
};
poet['born'];
poet.name;
poet.end;
// Error: Property 'end' does not exist on type '{born: number; name: string;}'

- 객체타입은 타입스크립트가 자바스크립트 코드를 이해하는 방법에 대한 핵심개념이다.
- nullundefined 를 제외한 모든 값은 그 값에 대한 실제타입의 멤버집합을 가지므로 타입스크립트는 모든 값의 타입을 확인하기 위해 객체타입을 이해해야한다.

* 객체타입 선언
- 기존 객체에서 직접 타입을 유추하는 것도 좋지만, 결국에는 객체의 타입을 명시적으로 선언하는게 좋다.
- 명시적으로 타입이 선언된 객체와는 별도로 객체의 형태를 설명하는 방법필요.
- 객체타입은 객체리터럴과 유사하게 보이지만 필드값 대신 타입을 사용해 설명한다. 

const poetLater: {
  born: number;
  name: string;
};
poetLater = {
  born: 1935,
  name: "Mary Oliver";
}
poetLater = "Sappho";
// Error: Type 'string' is not assignable to type '{born: number; name:string;}'


* 별칭객체 타입
{...} → 이렇게 객체타입을 계속 작성하지 말고 각 객체 타입에 타입 별칭을 할당해 사용하자, 타입스크립트의 할당 가능성 오류 메시지를 좀더 직접적으로 읽기 쉽게 만드는 추가이점있음.

type Poet = {
  born: number;
  name: string;
};
const poetLater: Poet;
poetLater = {
  born: 1935,
  name: "sara Teasdale"
};
poetLater = "Emily Dickinson";
// Error: Type 'string' is not assignable to "Poet'
 
- 대부분의 타입스크립트 프로젝트는 객체 타입을 설명할 때 인터페이스 키워드를 사용하는 것을 선호한다. 별칭 객체타입과 인터페이스는 거의 동일하다.
- 타입스크립트가 객체 리터럴을 해석하는 방법을 이해하자

구조적 타이핑

- 타입스크립트의 타입시스템은 구조적으로 타입화 되어있다., 타입을 충족하는 모든 값을 해당 타입으 ㅣ값으로 사용할 수 있다. 매개변수나 변수가 특정 객체 타입으로 선언되면 타입스크립트에 어떤 객체를 사용하든 해당 속성이 있어야 한다고 말해야한다.

type WithFirstName = {
  firstName: string;
};
type WithLastName = {
  lastName: string;
};
const hasBoth = {
  firstName: "Lucille",
  lastName: "Clifton"
};
const withFirstName: WithFirstName = hasBoth;
const withLastName: WithLastName = hasBoth;

	- 별칭객체타입인 WithFirstName 과 WithLastName 은 오직 string 타입의 단일멤버만 선언한다.
    - hasBoth 변수는 명시적으로 선언되지 않았음에도 두개의 별칭 객체타입을 모두 가지므로 두개의 별칭 객체 타입 내에 선언된 변수를 모두 제공할 수 있다.
    - 덕타이핑 : 동적 타이핑의 한 종류로 객체의 변수 및 메서드의 집합이 객체의 타입을 결정하는 것을 의미한다. 
    

사용검사

  • 객체타입으로 애너테이션 된 위치에 값을 제공할 때 타입스크립트는 값을 해당 깨체타입에 할당할 수 있는지 확인한다. 할당하는 값에는 객체타입의 필수속성이 있어야한다. 객체 타입에 필요한 멤버가 객체에 없다면타입스크립트는 타입 오류를 발생시킨다.
type FirstAndLastNames = {
  first: string;
  last: string;
};
consst hasBoth: FirstAndLastNames = {
  first: "Sarojini",
  last: "Naidu"
};
const hasOnlyOne: FirstAndLastNames = {
  // 두가지 속성이 모두 없는 객체는 사용할 수 없다
  //Error: Property 'last' is missing in type '{first: string}'
  // but required in type 'FirstAndLastNames'.
  first: "Sappho"
}

	- 별칭객체타입인 FirstAndLastNames 는 first와 last 속성이 모두 있어야 한다.
    - 두가지 속성을 모두 포함한 객체는 FirstAndLastNames 타입으로 선언된 변숭 ㅔ사용할 수 있지만  두가지 속성이 모두 없는 객체는 사용할 수 없다.
    - 둘 사이에 일치하지 않는 타입도 허용되지 않는다. 객체 타입은 필수속성 이름과 해당 속성이 예상되는 타입을 모두 지정한다. 객체의 속성이 일치하지 않으면 타입스크립트는 타입 오류를 발생시킨다.
    
    
    
type TimeRange = {
  start: Date;
};
const hasStartString: TimeRange = {
  start: "1879-02-13";
  //Error: Type 'string' is not assignable to type 'Date'.
}

	- TimeRange타입은 start속성을 Date타입으로 예상한다. 하지만, hasStartString객체의 start속성이 Date가 아니라 string타입이므로 타입오류 발생.
    
 

초과속성검사

  • 변수가 객체타입으로 선언되고, 초기값에 객체타입에서 정의된 것보다 많은 필드가 있다면 타입오류 발생.
  • 변수를 객체타입으로 선언하는 것은 타입검사기가 해당 타입에 예상되는 필드만 있는지 확인하는 방법이기도 하다.
//1.
type Poet = {
  born: number;
  name: string;
};
const poetMatch: Poet = {
  born: 1928,
  name: "Maya Angelou"
};
const extraProperty: Poet = {
  activity: "walking",
  //Error: Type '{activity: string; born: number; name: string;}'
  // is not assignable to type 'Poet'.
  // Object literal may only specify known properties,
  // and 'activity' does not exist in type 'Poet'.
  born: 1935,
  name: "Mary Oliver"
};

	- poetMatch변수는 별칭객체타입에 정의 된 필드가 Poet에 정확히 있지만, 초과 속성이 있는 extraProperty는 타입오류 발생시킴.
    - 초과 속성검사는 객체타입으로 선언된 위치에서 생성되는 객체 리터럴에 대해서만 일어난다. 기존 객체 리터럴을 제공하면 초과 속성 검사를 우회한다. 
    

//2.
const existingObject = {
  activity: "walking",
  born: 1935,
  name: "Mary Oliver"
};
const extraPropertyButOk: Poet = existingObjext;

	- extraPropertyButOk변수는 초기값이 구조적으로 Poet와 일치하기 때문에 타입오류가 발생하지 않음.
    

중첩된 객체타입

//1.
type Poem = {
  author: {
    firstName: string;
    lastName: string;
  };
  name: string;
};
const poemMatch: Poem = {
  author: {
    firstName: "Sylvia",
    lastName: "Plath"
  },
  name: "Lady Lazarus"
};
const poemMismatch: Poem = {
  author: {
    name: "Sylvia Plath"
    // Error: 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: "Tulips"
};

	- Poem타입은 author 속성이 firstName:string 과 lastName:string인 객체로 선언되었다.
    - poemMatch변수는 구조가 Poem과 일치하기 떄문에 Poem을 할당할 수 있지만,
    - poemMismatch는 author 속성에 firstName과 lastName 대신 name을 포함하니까 할당할 수 없음.
    
    
//2.
type Author = {
    firstName: string;
    lastName: string;
};

type Poem = {
    author: Author;
    name: string;
};

const poemMismatch: Poem = {
  author: {
    name: "Sylvia Plath"
    // Error: Type '{name: string;}' is not assignable to type 'Author'
    //  Object literal may only specify known properties,
    //  and 'name' does not exist in type 'Author'.
  },
  name: "Tulips"
};

	- 이렇게, 중첩된 객체타입을 고유한 타입이름으로 바꿔서 사용하면 코드와 오류메시지가 더 읽기 쉬워짐.

선택적속성

  • 모든객체에 객체타입 속성이 필요하진않다. 타입의 속성 애너테이션에서 : 앞에 ? 추가하면 선택적 속성.
//1.
type Book = {
  author?: string;
  pages: number;
};
const ok: Book = {
  author: "Rita Dove",
  pages: 80,
};
const missing: Book = {
  // Error: Property 'pages' is missing in type
  //	'{pages: number;}' but required in type 'Book'.
  author: "Rita Dove"
}
	- `선택적속성과 undefined를 포함함 유니언타입의 속성 사이에는 차이가 있다!!`
	- ?를 사용해 선택적으로 선언된 속성은 존재하지않아도 된다.
    - 필수로 선언된 속성과 | undefined 는 그 값이 undefined일지라도 반드시 존재해야함.
    
//2.
type Writers = {
  author: string | undefined;
  editor?: string;
};
const hasRequired: Writers = {
  author: undefined
};
const missingRequired: Writers = {};
//Error: Property 'author' is missing in type '{}' but required in type 'Writers';
	- Writers 타입의 editor 속성은 ? 를 사용해서 선언했으므로 변수를 선언할 때 생략이 가능하다.
    - author속성은 ? 가 없으므로 값이 undefined여도 반드시 존재해야한다.

객체타입유니언

  • 타입스크립트 코드에서는 속성이 조금다른, 하나 이상의 서로 다른 객체타입이 될 수 있는 타입을 설명할 수 있어야 한다. 또한 속성값을 기반으로 해당 객체 타입 간에 타입을 좁혀야 할수도 있다.

유추 된 객체 타입 유니언

  • 변수에 여러객체타입 중 하나가 될 수 있는 초기값이 주어지면 타입스크립트는 해당 타입을 객체 타입 유니언으로 유추한다.
    (유니언타입: 삼항연산자로 이거 아니면 저거인 타입)
  • 유니언타입은 가능한 각 객체 타입을 구성하고 있는 요솔ㄹ 모두 가질 수 ㅇ씨다. 객체 타입에 정의된 각각의 가능한 속성으 ㄴ비로 ㄱ 초기값이 없는 선택적 타입이지만 각 객체 타입의 구성요소로 주어진다.
//1.
const poem = Math.random() > 0.5 ? {
  name: "The Double Image", pages: 7
} : {
  name: "Her kind", rhymes: true
};
// 타입:
// {
//   name: string;
//   pages: number;
//   rhymes?: undefined;
// } | {
//   name: string;
//   pages?: undefined;
//   rhymes: boolean;
// }
poem.name; //string;
poem.pages; //number | undefined
poem.rhymes; //booleans | undefined

명시 된 객체타입 유니언

  • 객체타입의 조합을 명시하면 객체타입을 더 명확히 정의할 수 있다.
  • 코드를 더 작성해야하지만 객체타입을 더 많이 제어가능.
  • 특히, 값의 타입이 객체타입으로 구성 된 유니언이라면 타입스크립트의 타입시스템은 이런 모든 유니언 타입에 존재하는 속성에 대한 접근만 허용.
//1.
type PoemWithPages = {
  naem: string;
  pages: number;
};
type PoemWithRhymes = {
  name: string;
  rhymes: boolean;
};
type Poem = PoemWithPages | PoemWithRhymes;
const poem: Poem = Math.random() > 0.5
  ? {name: "The Double Image", pages: 7}
  : {name: "Her Kind", rhymes: true};
poem.name;
poem.pages;
//Error: Property 'pages' does not exist on type 'Poem'.
//	Property 'rhymes' does not exist on type 'PoemWithRhymes'.
poem.rhymes;
//Error: Property 'rhymes' does not exist on type 'Poem'.
//	Property 'rhymes' does not exist on type 'PoemWithPages'.
	- 잠재적으로 존재하지 않는 객체의 멤버에 대한 접근을 제한하면 코드의 안전을 지킬 수 있다.
    - 값이 여러타입 중 하나인 경우, 모든 타입에 존재하지 않는 속성이 객체에 존재할거라 보장할 수 없다. 
    

객체타입내로잉

  • 타입검사기가 유니언 타입 값에 특정 속성이 포함된 경우에만 코드 영역을 실행할 수 있음을 알게 되면 , 값의 타입을 해당 속성을 포함하는 구성요소로만 좁힌다. 즉, 코드에서 객체의 형태를 확인하고 타입내로잉이 객체에 적용된다.
//1.
if ("pages" in poem) {
  poem.pages;
} else {
  poem.rhymes;
}
	- poem의 pages가 타입스크립트의 타입가드 역할을 해서 PoemWithPages임을 나타내는지 확인한다.
    - 만일, Poem이 PoemWithPages가 아니라면 PoemWithRhymes이어야 함.
    - 타입스크립트는 if(poem.pages)와 같은 형식으로 참 여부를 확ㅇ니하는 것을 허용하지 않음.
    - 존재하지 않는 객체의 속성에 접근하려고 시도하면 타입 가드처럼 작동하는 방식으로 사용되더라도 타입오류로 간주됩니다. 

판별된 유니언

  • 자바스크립트와 타입스크립트에서 유니언 타입으로 된 객체의 또다른 인기있는 형태는 객체의 속성이 객체의 형태를 나타내도록하는 것.
  • 이런 타입형태를 판별된 유니언이라 부르고,
  • 객체의 타입을 가리키는 속성이 : 판별값 이다.
  • 타입스_는 코드에서 판별 속성을 사용해 타입내로잉을 수행한다.
//1. 
type PoemWithPages = {
  name: string;
  pages: number;
  type: 'pages';
};
type PoemWithRhymes = {
  name: string;
  rhymes: boolean;
  type: 'rhymes';
};
type Poem = PremWithPages | PoemWithRhymes;
const poem: Poem = Math.random() > 0.5
  ? {name: "the double Image", pages: 7, type: "pages"}
  : {name: "Her kind", rhymes: true, type: "rhymes"};
if (poem.type === "pages") {
  console.log('It's got pages: ${poem.pages}');
} else {
  console.log('It rhymes: ${poem.rhymes}');
}
poem.type;
poem.pages;
	- Poem타입은 PoemWithPages타입 또는 PoemWithRhymes타입 둘 다 될 수 있는 객체를 설명하고,
    - type 속성으로 어느 타입인지를 나타낸다.
    - 만일 poem.type이 pages이면, 타입스_는 poem을 PoemWithPages로 유추한다.
    - 타입내로잉 없이는 값에 존재하는 속성을 보장할 수 없다.
    

교차타입

  • 타입스크립트 유니언 타입은 둘 이상의 다른 타입 중 하나의 타입이 될 수 있다는 것을 나타낸다.
  • 자바스크립트의 런타임 | 연산자가 &연산자에 대응하는 역할을 하는 것처럼, 타입스크립트에서도 & 교차타입 intersection type을 사용해 여러타입을 동시에 나타낸다.
  • 교차타입은 일반적으로 여러 기존객체 타입을 별칭 객체 타입으로 결합해 새로운 타입을 생성한다.
//1.
type Artwork = {
  genre: string;
  name: string;
};
type Writing = {
  pages: number;
  name: string;
};
type WrittenArt = Artwork & Writing;
// 다음과 같음:
// {
//   genre: string;
//   name: string;
//   pages: number;
// }
	- Artwork 와 Writing 타입은 genre, name, pages 속성을 결합한 WrittenArt 타입을 형성하는데 사용됨.
    - 교차타입은 유니언타입과 결합할 수 있으며, 이는 하나의 타입으로 판별된 유니언타입을 설명하는데 유용.
    
    
//2.
type ShortPoem = {author: string} & (
  | {kigo: string; type: "haiku";}
  | {meter: number; type: "villanelle";}
);
const morningGlory: ShortPoem = {
  author: "Fukuda Chiyo-ni",
  kigo: "Morning Glory",
  type: "haiku"
};
const oneArt: ShortPoem = {
  //Error: Type '{author: string, type: "villanelle"}'
  //	is not assignable to type 'ShortPoem'.
  //	Type '{author: string, type: "villanelle"}' is not assignable to
  //	type '{author: string;} & {meter: number; type: "villanelle"}'
  //	Property 'meter' is missing in type '{author: string, type: "villanelle"}'
  //	but required in type '{meter: string, type: "villanelle"}'
  author: "Elizabeth Bishop",
  type: "villanelle"
};
	- ShortPoem 타입은 항상 author 속성을 가지며 하나의 type 속성으로 판별된 유니언타입이다.

긴 할당 가능성 오류

//1.

type ShortPoemBase = {author: string;};
type Haiku = ShortPoemBase & {kigo: string; type: 'haiku'};
type Villanelle = ShortPoemBase & {meter: number; type: 'villanelle'};
type ShortPoem = Haiku | Villanelle;

const onArt: ShortPoem = {
  //Error: Type '{author: string, type: "villanelle"}'
  //	is not assignable to type 'ShortPoem'.
  //	Type '{author: string, type: "villanelle"}' is not assignable to type 'Villanelle'.
  //	Property 'meter' is missing in type '{author: string, type: "villanelle"}'
  //	but required in type '{meter: number, type: "villanelle"}'
  author: "Elizabeth Bishop",
  type: "villanelle"
};

never

  • 교차타입은 잘못 사용하기 쉽고 불가능한 타입을 생성한다. 원시타입의 값은 동시에 여러 타입이 될 수 없기 때문에 교차타입의 구성요소로 함께 결합할 수 없다. 두개의 원시타입을 함께 시도하면 never키워드로 표시되는 never타입이 된다.
type NotPossible = number & string;
	- never키워드와 never타입은 프로그래밍 언어에서 bottom타입 또는 empty타입을 뜻한다.
    - bottom타입은 값을 가질 수 없고 참조할 수 없는 타입이므로 bottom 타입에 그 어떠한 타입도 제공못함.

const notNumber: NotPossible = 0;
// Error: Type 'number' is not assingnable to type 'never'.
const notString: never = '';
// Error: Type 'string' is not assignable to type 'never'.
	- 대부분의 타입스크립트 프로젝트는 never타입을 거의 사용하지 않지만 코드에서 불가능한 상태를 나타내기 위해 가끔 등장.
    - 하지만 대부분 교차타입을 잘못 사용해 발생한 실수일 가능성이 높다.

0개의 댓글