정보실

웹학교

정보실

javascript 결정적인 TypeScript 핸드북

본문

90,000 개발자의 스택 오버플로 설문 조사에 따르면 TypeScript는 사람들이 가장 배우고 싶어하는 도구 중 하나입니다.


TypeScript는 지난 몇 년 동안 인기, 커뮤니티 규모 및 채택이 폭발적으로 증가했습니다. 현재 Facebook의 Facebook Jest 프로젝트조차도 TypeScript로 이동하고 있습니다.


TypeScript 란 무엇입니까? 


TypeScript는 정적으로 형식화 된 JavaScript 수퍼 세트로, 대규모 자바 스크립트 응용 프로그램 개발을 용이하게 합니다. 또한 확장되는 JavaScript라고도 합니다.


왜 TypeScript를 사용합니까? 


지난 몇 년 동안 JavaScript는 많은 발전을 거듭했습니다. 클라이언트와 서버 측 모두에 사용되는 가장 다목적 크로스 플랫폼 언어입니다.


그러나 JavaScript는 이러한 대규모 응용 프로그램 개발을 위한 것이 아닙니다. 유형 시스템이 없는 동적 언어이므로 변수는 문자열 또는 부울과 같은 모든 유형의 값을 가질 수 있습니다.


유형 시스템은 코드 품질, 가독성을 높이고 코드베이스를 쉽게 유지 관리하고 리팩터링 합니다. 더 중요한 것은 런타임이 아닌 컴파일 타임에 오류가 발생할 수 있다는 것입니다.


유형 시스템이 없으면 동일한 코드로 작업하는 대규모 팀과 함께 복잡한 응용 프로그램을 빌드 하기 위해 JavaScript를 확장하기가 어렵습니다.


TypeScript는 컴파일 타임에 코드의 다른 부분 사이를 보장합니다. 컴파일러 오류는 일반적으로 문제가 발생한 위치와 정확히 무엇이 잘못 되었는지를 알려주는 반면 런타임 오류에는 오도를 일으킬 수 있는 스택 추적이 수반되며 디버그 작업에 많은 시간이 소요됩니다.


TypeScript 전문가 


  1. 개발 주기 초기에 잠재적인 오류를 파악하십시오.
  2. 큰 코드베이스를 관리합니다.
  3. 더 쉬운 리팩토링.
  4. 팀에서 보다 쉽게 ​​작업 할 수 있도록 — 코드 계약이 강력 할 때 다른 개발자가 의도하지 않은 방식으로 코드베이스를 출입하는 것이 더 쉽습니다.
  5. 문서 — 유형은 미래의 자기 자신과 다른 개발자가 따를 수 있는 일종의 문서를 알려줍니다.


TypeScript 단점 


  1. 학습해야 할 추가 사항입니다. 단기적인 둔화와 장기적인 효율성 및 유지 보수 개선 간의 상충 관계입니다.
  2. 형식 오류가 일치하지 않을 수 있습니다.
  3. 구성은 동작을 크게 변경합니다.


Types 


Boolean 

const isLoading: boolean = false;

Number 

const decimal: number = 8;
const binary: number = 0b110;

String 

const fruit: string = "orange";

Array 

배열 유형은 다음 두 가지 방법 중 하나로 쓸 수 있습니다.

// Most common
let firstFivePrimes: number[] = [2, 3, 5, 7, 11];
// Less common. Uses generic types (more on that later)
let firstFivePrimes2: Array<number> = [2, 3, 5, 7, 11];

Tuple 

튜플 유형을 사용하면 고정 된 수의 요소 유형이 알려진 체계적인 배열을 표현할 수 있습니다. 이것은 오류가 발생한다는 것을 의미합니다

let contact: [string, number] = ['John', 954683];
contact = ['Ana', 842903, 'extra argument']  /* Error! 
Type '[string, number, string]' is not assignable to type '[string, number]'. */

Any 

any는 유형 시스템의 모든 유형과 호환되므로 무엇이든 할당 할 수 있으며 모든 유형에 할당 할 수 있습니다. 유형 검사를 거부 할 수 있습니다.

let variable: any = 'a string';
variable = 5;
variable = false;
variable.someRandomMethod(); /* Okay, 
someRandomMethod might exist at runtime. */

Void 

void는 모든 유형이 전혀 없다는 것입니다. 일반적으로 값을 반환하지 않는 함수의 반환 유형으로 사용됩니다.

function sayMyName(name: string): void {
  console.log(name);
}
sayMyName('Heisenberg');

Never 

never 유형은 절대 발생하지 않는 값의 유형을 나타냅니다. 예를 들어, 항상 예외를 던지거나 끝점에 도달하지 않는 함수의 반환 유형은 결코 아닙니다.

// throws an exception
function error(message: string): never {
  throw new Error(message);
}

// unreachable end point
function continuousProcess(): never {
  while (true) {
      // ...
  }
}

Null and Undefined 

undefined와 null은 모두 각각 undefined와 null이라는 자체 유형을 갖습니다. 공허와 마찬가지로 그것들은 그 자체로는 별로 유용하지 않지만 공용체 유형 내에서 사용될 때 유용합니다 (더 조금)

type someProp = string | null | undefined;


Unknown 

TypeScript 3.0에는 알려지지 않은 형식이 있습니다. 알 수 없는 것은 무엇이든 지정할 수 있지만 알 수 없는 것은 그 자체와 다른 것 외에는 지정할 수 없습니다. 먼저 더 구체적인 유형을 주장하거나 좁히지 않으면 알 수 없는 작업이 허용되지 않습니다.

type I1 = unknown & null;    // null
type I2 = unknown & string;  // string
type U1 = unknown | null;    // unknown
type U2 = unknown | string;  // unknown

Type Alias 

유형 별명은 여러 위치에서 사용할 수 있는 유형 주석의 이름을 제공합니다. 다음 구문을 사용하여 작성됩니다.

type Login = string;

Union Type 

TypeScript를 사용하면 속성에 둘 이상의 데이터 형식을 사용할 수 있습니다. 이것을 유니온 타입이라고 합니다.

type Password = string | number;

Intersection Type 

교차 유형은 모든 멤버 유형의 속성을 결합하는 유형입니다.

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

interface Worker {
  companyId: string;
}

type Employee = Person & Worker;

const bestOfTheMonth: Employee = {
  name: 'Peter'
  age: 39,
  companyId: '123456'

Interface 


인터페이스는 이름이 지정된 단일 주석에서 해당 유형 주석으로 예상되는 속성을 정확히 지정하는 컴파일러와의 계약과 같습니다.

참고 사항 : 인터페이스는 런타임 JS 영향이 거의 없으며 유형 검사에만 사용됩니다.

  • 인터페이스 개체가 이러한 속성을 정의하거나 정의하지 않을 수 있음을 의미하는 선택적 속성을?로 표시하는 선택적 속성을 선언 할 수 있습니다.
  • 읽기 전용 속성을 선언 할 수 있습니다. 즉, 속성에 값이 할당되면 변경할 수 없습니다.
interface ICircle {
  readonly id: string;
  center: {
    x: number;
    y: number;
  },
  radius: number;
  color?: string;  // Optional property
}
  
const circle1: ICircle = {
  id: '001',
  center: { x: 0 },
  radius: 8,
};  /* Error! Property 'y' is missing in type '{ x: number; }' 
but required in type '{ x: number; y: number; }'. */

const circle2: ICircle = {
  id: '002',
  center: { x: 0, y: 0 },
  radius: 8,
}  // Okay

circle2.color = '#666';  // Okay
circle2.id = '003';  /* Error! 
Cannot assign to 'id' because it is a read-only property. */

Extending Interfaces 


인터페이스는 하나 이상의 인터페이스를 확장 할 수 있습니다. 따라서 인터페이스 작성이 유연하고 재사용 가능합니다.

interface ICircleWithArea extends ICircle {
  getArea: () => number;
}

const circle3: ICircleWithArea = {
  id: '003',
  center: { x: 0, y: 0 },
  radius: 6,
  color: '#fff',
  getArea: function () {
    return (this.radius ** 2) * Math.PI;
  },
};

Implementing an Interface 


인터페이스를 구현하는 클래스는 인터페이스의 구조를 엄격하게 준수해야 합니다.

interface IClock {
  currentTime: Date;
  setTime(d: Date): void;
}

class Clock implements IClock {
  currentTime: Date = new Date();
  setTime(d: Date) {
    this.currentTime = d;
  }
  constructor(h: number, m: number) { }
}

Enums 


enum (또는 열거 형)은 숫자 또는 문자열 값일 수 있는 관련 값 모음을 구성하는 방법입니다.

enum CardSuit {
  Clubs,
  Diamonds,
  Hearts,
  Spades
}

let card = CardSuit.Clubs;

card = "not a card suit"; /* Error! Type '"not a card suit"' 
is not assignable to type 'CardSuit'. */

후드에서 열거 형은 기본적으로 숫자를 기반으로 합니다. 열거 형 값은 0부터 시작하여 각 멤버마다 1 씩 증가합니다.


이전 예제에서 생성 된 JavaScript 코드 :

var CardSuit;
(function (CardSuit) {
  CardSuit[CardSuit["Clubs"] = 0] = "Clubs";
  CardSuit[CardSuit["Diamonds"] = 1] = "Diamonds";
  CardSuit[CardSuit["Hearts"] = 2] = "Hearts";
  CardSuit[CardSuit["Spades"] = 3] = "Spades";
})(CardSuit || (CardSuit = {}));

/**
 * Which results in the following object:
 * {
 *   0: "Clubs",
 *   1: "Diamonds",
 *   2: "Hearts",
 *   3: "Spades",
 *   Clubs: 0,
 *   Diamonds: 1,
 *   Hearts: 2,
 *   Spades: 3
 * }
 */

또는 열거 형을 보다 읽기 쉬운 접근 방식 인 문자열 값으로 초기화 할 수 있습니다.

enum SocialMedia {
  Facebook = 'FACEBOOK',
  Twitter = 'TWITTER',
  Instagram = 'INSTAGRAM',
  LinkedIn = 'LINKEDIN'
}

역 매핑 


enum은 역 매핑을 지원하므로 멤버의 값과 멤버 이름에서 액세스 할 수 있습니다. 

CardSuit 예제로 돌아가서 :

const clubsAsNumber: number = CardSuit.Clubs; // 3
const clubsAsString: string = CardSuit[0];    // 'Clubs'

Functions 


각 매개 변수에 유형을 추가 한 다음 함수 자체에 리턴 유형을 추가 할 수 있습니다.

function add(x: number, y: number): number {
  return x + y;
}

Function Overloads 


TypeScript를 사용하면 함수 오버로드를 선언 할 수 있습니다. 기본적으로 이름은 같지만 매개 변수 유형과 리턴 유형이 다른 여러 함수를 가질 수 있습니다. 다음 예제를 고려하십시오.

function padding(a: number, b?: number, c?: number, d?: any) {
  if (b === undefined && c === undefined && d === undefined) {
    b = c = d = a;
  }
  else if (c === undefined && d === undefined) {
    c = a;
    d = b;
  }
  return {
    top: a,
    right: b,
    bottom: c,
    left: d
  };
}

각 매개 변수의 의미는 함수에 전달되는 매개 변수 수에 따라 달라집니다. 또한 이 기능은 하나, 둘 또는 네 개의 매개 변수 만 필요합니다. 함수 오버로드를 만들려면 함수 헤더를 여러 번 선언하면 됩니다. 마지막 함수 헤더는 실제로 함수 본문 내에서 활성화되지만 외부 세계에서는 사용할 수 없는 헤더입니다.

function padding(all: number);
function padding(topAndBottom: number, leftAndRight: number);
function padding(top: number, right: number, bottom: number, left: number);
function padding(a: number, b?: number, c?: number, d?: number) {
  if (b === undefined && c === undefined && d === undefined) {
    b = c = d = a;
  }
  else if (c === undefined && d === undefined) {
    c = a;
    d = b;
  }
  return {
    top: a,
    right: b,
    bottom: c,
    left: d
  };
}

padding(1);       // Okay
padding(1,1);     // Okay
padding(1,1,1,1); // Okay
padding(1,1,1);   /* Error! No overload expects 3 arguments, but
overloads do exist that expect either 2 or 4 arguments. */

Classes 


속성 및 메소드의 인수에 유형을 추가 할 수 있습니다

class Greeter {
  greeting: string;
  constructor(message: string) {
    this.greeting = message;
  }
  greet(name: string) {
    return `Hi ${name}, ${this.greeting}`;
  }
}

Access Modifiers 


Typescript는 클래스 멤버의 접근성을 결정하는 공개, 비공개, 보호 된 수정자를 지원합니다.

  • 공개 멤버는 일반 JavaScript 멤버와 동일하게 작동하며 기본 수정 자입니다.
  • 포함 된 클래스 외부에서는 개인 멤버에 액세스 할 수 없습니다.
  • 보호 된 멤버는 파생 클래스 내에서 액세스 할 수 있으므로 개인과 다릅니다.
| Accessible on  | public | protected | private |
| :------------- | :----: | :-------: | :-----: |
| class          |   yes  |    yes    |   yes   |
| class children |   yes  |    yes    |    no   |
| class instance |   yes  |     no    |    no   |

읽기 전용 수정자 (Readonly modifier) 


읽기 전용 속성은 선언 또는 생성자에서 초기화해야 합니다.

class Spider {
  readonly name: string;
  readonly numberOfLegs: number = 8;
  constructor (theName: string) {
    this.name = theName;
  }
}

Parameter properties 


매개 변수 속성을 사용하면 한 곳에서 멤버를 만들고 초기화 할 수 있습니다. 이들은 생성자 매개 변수 앞에 수정자를 접두어로 선언합니다.

class Spider {
  readonly numberOfLegs: number = 8;
  constructor(readonly name: string) {
  }
}

Abstract 


abstract 키워드는 클래스와 추상 클래스 메서드 모두에 사용할 수 있습니다.

  • 추상 클래스는 직접 인스턴스화 할 수 없습니다. 그것들은 주로 추상 클래스를 확장하는 클래스가 모든 추상 메소드를 정의해야 하는 상속을 위한 것입니다.
  • 추상 멤버는 구현을 포함하지 않으므로 직접 액세스 할 수 없습니다. 이 멤버는 자식 클래스 (인터페이스와 같은 클래스)로 구현되어야 합니다.

Type Assertion 


TypeScript를 사용하면 원하는 방식으로 유추 된 유형을 재정의 할 수 있습니다. 이것은 컴파일러 자체보다 변수 유형에 대해 더 잘 이해할 때 사용됩니다. 

const friend = {};
friend.name = 'John';  // Error! Property 'name' does not exist on type '{}'

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

const person = {} as Person;
person.name = 'John';  // Okay

원래 형식 어설 션의 구문은 <type>입니다.

let person = <Person> {};

그러나 이것은 JSX에서 사용될 때 모호성을 만들었습니다. 따라서 대신 사용하는 것이 좋습니다.


유형 어설 션은 일반적으로 JavaScript에서 코드를 마이그레이션 할 때 사용되며 현재 지정된 것보다 더 정확한 변수 유형을 알고 있을 수 있습니다. 그러나 주장은 유해한 것으로 간주 될 수 있습니다.


이전 예제에서 Person 인터페이스를 살펴 보겠습니다. 당신은 뭔가 잘못 알아? 누락 된 부동산 연령을 발견 한 경우 축하합니다! 컴파일러는 Person의 속성에 자동 완성 기능을 제공하는 데 도움이 될 수 있지만 속성을 놓친 경우 불평하지 않습니다.


Type Inference 


TypeScript는 형식 주석 형식으로 제공되는 명시 적 정보가 없을 때 변수 유형을 유추합니다.

/**
 * Variable definitinon
 */
let a = "some string";
let b = 1;
a = b;  // Error! Type 'number' is not assignable to type 'string'.

// In case of complex objects, TypeScript looks for the most common type
// to infer the type of the object.
const arr = [0, 1, false, true];  // (number | boolean)[]


/**
 * Function return types
 */
function sum(x: number, y: number) {
  return x + y;  // infer to return a number
}

Type Compatibility 


형식 호환성은 구조적 타이핑을 기반으로 하며 멤버에만 기반한 형식과 관련됩니다.


구조적 유형의 기본 규칙은 y가 x와 같은 구성원을 갖는 경우 x가 y와 호환된다는 것입니다.

interface Person {
  name: string;
}

let x: Person;  // Okay, despite not being an implementation of the Person interface
let y = { name: 'John', age: 20 };  // type { name: string; age: number }
x = y;

// Please note that x is still of type Person. 
// In the following example, the compiler will show an error message as it does not
// expect the property age in Person but the result will be as expected:
console.log(x.age); // 20

y에는 멤버 이름 : 문자열이 있으므로 Person 인터페이스의 필수 특성과 일치하므로 x는 y의 하위 유형임을 의미합니다. 따라서 과제가 허용됩니다.


Functions 


Number of arguments 


함수 호출에서 최소한 충분한 인수를 전달해야 합니다. 즉, 추가 인수는 오류를 발생 시키지 않습니다.

function consoleName(person: Person) {
  console.log(person.name);
}
consoleName({ name: 'John' });           // Okay
consoleName({ name: 'John', age: 20 });  // Extra argument still Okay

Return type 


리턴 유형은 최소한 충분한 데이터를 포함해야 합니다.

let x = () => ({name: 'John'});
let y = () => ({name: 'John', age: 20 });
x = y;  // OK
y = x;  /* Error! Property 'age' is missing in type '{ name: string; }'
but required in type '{ name: string; age: number; }' */

Type Guard 


타입 가드를 사용하면 조건부 블록 내에서 객체의 유형을 좁힐 수 있습니다.


typeof 


조건부 블록에서 typeof를 사용하면 컴파일러는 변수의 유형이 다르다는 것을 알게 됩니다. 다음 예제에서 TypeScript는 조건부 블록 외부에서 x가 부울 일 수 있으며 toFixed에 대한 함수를 호출 할 수 없음을 이해합니다.

function example(x: number | boolean) {
  if (typeof x === 'number') {
    return x.toFixed(2);
  }
  return x.toFixed(2); // Error! Property 'toFixed' does not exist on type 'boolean'.
}

instanceof

class MyResponse {
  header = 'header example';
  result = 'result example';
  // ...
}
class MyError {
  header = 'header example';
  message = 'message example';
  // ...
}
function example(x: MyResponse | MyError) {
  if (x instanceof MyResponse) {
    console.log(x.message); // Error! Property 'message' does not exist on type 'MyResponse'.
    console.log(x.result);  // Okay
  } else {
    // TypeScript knows this must be MyError

    console.log(x.message); // Okay
    console.log(x.result);  // Error! Property 'result' does not exist on type 'MyError'.
  }
}

in 

in 연산자는 객체에 속성이 있는지 확인합니다.

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

const person: Person = {
  name: 'John',
  age: 28,
};

const checkForName = 'name' in person; // true

Literal Types 


리터럴은 JavaScript 프리미티브 인 정확한 값입니다. 그것들은 유용한 추상화를 생성하기 위해 타입 조합으로 결합 될 수 있습니다.

type Orientation = 'landscape' | 'portrait';
function changeOrientation(x: Orientation) {
  // ...
}
changeOrientation('portrait'); // Okay
changeOrientation('vertical'); /* Error! Argument of type '"vertical"' is not 
assignable to parameter of type 'Orientation'. */

Conditional Types 


조건부 유형은 유형 관계 테스트를 설명하고 해당 테스트 결과에 따라 두 가지 가능한 유형 중 하나를 선택합니다.

type X = A extends B ? C : D;

이는 유형 A가 유형 B에 지정 될 수 있는 경우 X는 C와 동일한 유형입니다. 그렇지 않으면 X는 유형 D와 같습니다.


Generic Types 


일반 유형은 완료하기 위해 다른 유형을 포함하거나 참조해야 하는 유형입니다. 다양한 변수 간에 의미 있는 제약 조건을 적용합니다. 다음 예제에서 함수는 전달하는 모든 유형의 배열을 반환합니다.

function reverse<T>(items: T[]): T[] {
  return items.reverse();
}
reverse([1, 2, 3]); // number[]
reverse([0, true]); // (number | boolean)[]

keyof 


keyof 연산자는 주어진 유형에 대한 키 세트를 조회합니다.

interface Person {
  name: string;
  age: number;
}
type PersonKeys = keyof Person; // 'name' | 'age'

Mapped Types 


매핑 된 유형을 사용하면 속성 유형을 매핑하여 기존 유형에서 새 유형을 만들 수 있습니다. 기존 유형의 각 속성은 지정한 규칙에 따라 변환됩니다.


Partial 

type Partial<T> = {
  [P in keyof T]?: T[P];
}
  • 일반 부분 유형은 단일 유형 매개 변수 T로 정의됩니다.
  • keyof T는 T의 모든 속성 이름을 문자열 리터럴 형식으로 통합합니다.
  • [T의 키의 P] ?: T [P]는 유형 T의 각 특성 P의 유형이 선택적이고 T [P]로 변환되어야 함을 나타낸다.
  • T [P]는 유형 T의 특성 P의 유형을 나타냅니다.


Readonly 


인터페이스 섹션에서 다룬 것처럼 TypeScript를 사용하면 읽기 전용 속성을 만들 수 있습니다. 유형 T를 사용하고 모든 속성을 읽기 전용으로 설정하는 읽기 전용 유형이 있습니다.

type Readonly<T> = {
  readonly [P in keyof T]: T[P];
};

Exclude 


제외를 사용하면 다른 유형에서 특정 유형을 제거 할 수 있습니다. T에 할당 가능한 모든 것을 T에서 제외하십시오.

/**
 * type Exclude<T, U> = T extends U ? never : T;
 */
type User = {
  _id: number;
  name: string;
  email: string;
  created: number;
};

type UserNoMeta = Exclude<keyof User, '_id' | 'created'>

Pick 


선택을 사용하면 다른 유형에서 특정 유형을 선택할 수 있습니다. T에 할당 가능한 Tanything에서 선택하십시오.

/**
 * type Pick<T, K extends keyof T> = {
 *   [P in K]: T[P];
 *  };
 */
type UserNoMeta = Pick<User, 'name' | 'email'>

infer 


infer 키워드를 사용하여 조건부 유형의 extendsclause 내에서 유형 변수를 유추 할 수 있습니다. 이러한 유추 된 유형 변수는 조건부 유형의 실제 분기에서만 사용할 수 있습니다.


ReturnType 


함수의 반환 유형을 가져옵니다.

/**
 * Original TypeScript's ReturnType
 * type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any;
 */
type MyReturnType<T> = T extends (...args: any) => infer R ? R : any;

type TypeFromInfer = MyReturnType<() => number>;  // number
type TypeFromFallback = MyReturnType<string>;     // any

MyReturnType을 분류 해 봅시다 :

  • T의 반환 유형은…
  • 우선, T는 함수입니까?
  • 그렇다면 유형이 유추 된 리턴 유형 R로 해석됩니다.
  • 그렇지 않으면 유형이 any으로 해석됩니다.


References & Useful Links 


https://basarat.gitbooks.io/typescript/

https://www.typescriptlang.org/docs/home.html

https://www.tutorialsteacher.com/typescript

https://github.com/dzharii/awesome-typescript

https://github.com/typescript-cheatsheets/react-typescript-cheatsheet


TypeScript를 공부하고 시험해보기 위해 TS와 React-Native를 사용하여 간단한 CurrencyConverter 앱을 만들었습니다. 이 프로젝트를 여기서 확인할 수 있습니다.






  • 트위터로 보내기
  • 페이스북으로 보내기
  • 구글플러스로 보내기
  • 카카오톡으로 보내기

페이지 정보

조회 71회 ]  작성일19-08-17 14:39

웹학교