728x90
반응형

TypeScript는 JavaScript의 기능들을 제공하면서 그 위에 자체 레이어를 추가한다.

JavScript는 string, number, object, undefined 같은 타입을 가지고 있지만, 할당되었는지 미리 확인해 주지 않는다.

타입 정의하기(Defining Types)

객체의 형태를 명시적으로 나타내기 위해서는 interface로 선언한다.

const user = {
  name: "Hayes",
  id: 0,
};
interface User {
  name: string;
  id: number;
}

const user:User = {
	name: "Hayes",
	id: 0,
}

해당 interface에 맞지 않는 객체를 생성하면 TypeScript는 경고를 준다.

TypeScript는 JavaScript와 마찬가지로 객체 지향 프로그래밍을 지원한다.

interface User{
	name:string;
	id:number;
}

class UserAccount {
	name:string;
	id:number;

	constructor(name:string,id:number){
		this.name=name;
		this.id=id;
	}
}

const user:User = new UserAccount("Murphy",1);

인터페이스는 함수에서 매개변수와 리턴 값을 명시하는데 사용되기도 한다.

interface User {
  name: string;
  id: number;
}

function getAdminUser(): User {
  //...
}

function deleteUser(user: User) {
  // ...
}

JavaScript에서 사용했던 boolean, bigint, null, number, string, symbol, object, undefined는 당연히 사용할 수 있고, 여기에 더하여

any (무엇이든 허용)

unknown (타입이 무엇인지 확인)

never (이 타입은 발생될 수 없다)

void (undefined를 리턴하거나 리턴 값이 없음)

interface를 우선적으로 사용하고, 특정 기능이 필요할 때 type을 사용해야 한다.

타입 구성 (Composing Types)

여러가지 타입을 이용하여 새 타입을 작성하기 위해 Union과 Generic을 사용한다.

유니언(Unions)

타입이 여러 타입 중 하나일 수 있음을 선언하는 방법이다.

예를 들어 boolean 타입을 true 또는 false로 설명할 수 있다.

type MyBool = true | false;

유니언 타입이 가장 많이 사용된 사례 중 하나는 값이 string 또는 number의 리터럴 집합을 설명하는 것이다

type WindowStates = "open" | "closed" | "minimized";
type LockStates = "locked" | "unlocked";
type OddNumbersUnderTen = 1 | 3 | 5 | 7 | 9;
function getLength(obj: string | string[]) {
  return obj.length;
}
// 이건 array 또는 string을 받는 함수라는 뜻이다.

제네릭(Generics)

제네릭은 이전 글에서 공부했었는데, 타입에 변수를 제공하는 방법이다.

제네릭이 없는 배열은 어떤 것이든 포함할 수 있다.

제네릭이 있는 배열은 배열 안의 값을 설명할 수 있다.

type StringArray = Array<string>;
type NumberArray = Array<number>;
type ObjectWithNameArray = Array<{ name: string }>;

구조적 타입 시스템 (Structural Type System)

타입 검사가 값이 있는 형태에 집중한다.

구조적 타입 시스템에서 두 객체가 같은 형태를 가지면 같은 것으로 간주된다.

interface Point {
  x: number;
  y: number;
}

function printPoint(p: Point) {
  console.log(`${p.x}, ${p.y}`);
}

// "12, 26"를 출력합니다
const point = { x: 12, y: 26 };
printPoint(point);

여기서 point 변수는 Point 타입으로 선언된 적이 없지만, TypeScript는 타입 검사에서 point의 형태와 Point의 형태를 비교하여 같은 형태이기 때문에, 통과한다.

TypeScript 설치

2가지 방법으로 설치할 수 있다.

  1. npm을 이용 (Node.js 패키지 매니저)
  2. TypeScript의 Visual Studio 플러그인 설치
npm install -g typescript

코드 컴파일

tsc temp.ts
728x90
반응형

'프론트엔드 > TypeScript' 카테고리의 다른 글

Generic  (0) 2022.07.12
728x90
반응형

제네릭은 어떠한 클래스 혹은 함수에서 사용할 타입을 그 함수나 클래스를 사용할 때 결정하는 프로그래밍 기법을 말한다.

Java나 C++등의 정적 타입 언어에서는 함수 및 클래스를 선언하는 시점에서 매개변수 혹은 리턴 타입을 정의해야하기 때문에 기본적으로 특정 타입을 위해 만들어진 클래스나 함수를 다른 타입을 위해 재사용할 수 없다.

 

그래서 제네릭을 통해 함수와 클래스의 범용적인 사용을 가능하게 한다.

JavaScript는 타입 에러를 런타임에서 일으킨다. 코드를 실행시키기 전까지는 함수와 클래스가 모든 타입에 대응하기 때문에 JavaScript에서는 필요가 없다.

 

제네릭은 꺽쇠를 넣고 그 안에 타입으로 사용되는 식별자를 집어넣는다. 클래스에서 제네릭을 사용하겠다고 선언한 경우 T는 해당 클래스에서 사용할 수 있는 특정한 타입이 된다.

 

배열을 입력으로 받아 그 배열의 첫번째 요소를 출력하고 싶은 경우, 제네릭을 쓰는 것과 안 쓰는 경우를 비교해보자.

 

function first(arr:any[]):any {
	return arr[0];
}

위의 코드는 어떤 타입의 배열이라도 받을 수 있기 때문에 리턴하게 되는 타입이 무엇인지 알 수 없다.

 

function first<T>(arr: T[]):T {
	return arr[0];
}
first<number>([1,2,3]); // 1

사용할 때는 함수를 호출할 때 제네릭 문법으로 타입을 정해주기만 하면 된다.

 

다음과 같은 배열이 주어졌을 때, age가 가장 높은 요소를 반환하는 함수를 구현한다고 해보자.

const ages = [
	{ age: 10 },
	{ age: 12 },
	{ age: 19 },
	{ age: 22 },
]

typescript를 사용하지 않는다면 이런 식으로 작성한다.

  • code
  • function getOldest(ages) { return ages.sort((a, b) => b.age - a.age)[0]; /* const sortedAges = ages.sort((a, b) => b.age - a.age); return sortedAges[0]; */ }

하지만 typescript로는 이렇게 작성해야 한다.

  • code
  • type ageObj = { age: number } function getOldest(ages: ageObj[]): ageObj { return ages.sort((a, b) => b.age - a.age)[0]; }

자 하지만 만약 객체가 더 복잡한 형태면 어떻게 해야 할까?

예를 들어 ages가 아닌 persons 배열이 주어졌다고 해보자.

const persons = [
	{ name: "jinho", age: 22, gender: "male", address: "A"},
	{ name: "jinho2", age: 18, gender: "male", address: "B"},
	{ name: "jinho3", age: 28, gender: "male", address: "C"},
]

const oldestPerson = getOldest(persons);

이렇게 되면 우리의 oldestPerson 변수는 { name: string, age: number, gender: string, address: string } 의 타입이 아닌 ageObj 타입을 가지게 된다. 따라서 아래의 동작은 오류를 발생시킨다.

console.log(oldestPerson.name) 
// type error: Property 'name' does not exist on type 'ageObj'.

여기서 우리는 getOldest 함수가 조금 더 타입에 자유롭도록 하기 위해 generic을 사용해야 한다.

function getOldest<T extends ageObj>(ages: T[]): T {
	return ages.sort((a, b) => b.age - a.age)[0];
}

const persons = [
	{ name: "jinho", age: 22, gender: "male", address: "A"},
	{ name: "jinho2", age: 18, gender: "male", address: "B"},
	{ name: "jinho3", age: 28, gender: "male", address: "C"},
]

interface IPerson {
	name: string;
	age: number;
	gender: string;
	address: string;
}

const oldestPerson = getOldest<IPerson>(persons);

 

 

import React from 'react'

const App = (): JSX.Element => {
	const [count, setCount] = React.useState(0);

	const addCount = () => setCount(count + 1);
	const minusCount = () => setCount(count - 1);

	return <div>{count}</div>
}

 

import React from 'react'

interface IPerson {
	name: string;
	age: number;
	gender: string;
	address: string;
}

const App = (): JSX.Element => {
	const [person, setPerson] = React.useState<IPerson>({
		name: "",
		age: 0,
		gender: "",
		address: "",
	});

	React.useEffect(() => {
		// data fetching -> setPerson(불러온 데이터)
	}, [])

	return <div>{person.name}</div>
}
728x90
반응형

'프론트엔드 > TypeScript' 카테고리의 다른 글

TypeScript 설치와 사용  (0) 2022.07.13

+ Recent posts