타입스크립트를 알아보자!
타입스크립트는 자바스크립트의
// Child.tsx
interface ChildProps {
color: string;
onClick: () => void;
}
export const Child = ({ color, onClick }: ChildProps) => {
return <div onClick={onClick}>{color}</div>
}
// Parent.tsx
import { Child } from './Child';
const Parent = () => {
return <Child color="red" onClick={() => console.log('hi')} />
};
React.FC<>
를 명시함으로서 해당 함수가 리액트의 컴포넌트라는 걸 알려줄 수 있다.
React.FC<프롭타입>
제네릭에 프롭타입을 적어서 props의 타입도 정의할 수 있다.
export const ChildAsFC: React.FC<ChildProps> = ({ color }) => {
return <div>{color}</div>
}
useState 사용 시 useState의 제네릭 부분에 타입을 명시할 수 있다.
단순 string, number 등은 타입스크립트가 추론할 수 있지만 array, object등은 따로 적어줄 필요가 있다
const Example: React.FC = () => {
const [name, setName] = useState('');
const [lists, setLists] = useState<string[]>([]);
const handleClick = () => {
setLists([...lists, name]);
}
//...
}
// const [lists, setLists] = useState([]);
// 타입을 안적으면 lists의 타입은 never[]가 되어 에러가 발생한다
자바스크립트는 수정할 일이 생기면 프로젝트에서는 복잡합니다.
type 관련된 버그들이 많이 발생합니다. 남이 짠 코드에 뭔가를 더하거나 수정할 때
알 수 없는 타입관련 버그들이 생길텐데 이럴 때 타입스크립트로 만들어졌길 바래야 합니다.
타입스크립트를 쓰면 에러메세지도 더 정확해집니다.
엄격한 타입룰 덕분에 "숫자가 들어와야하는데 왜 문자를 쓰니?" "object에 apend()라는 건 없어, append()말하는거 아니야?" 라던지 이렇게 친절하게 알려줍니다.
let 이름:string = 'kim'
변수를 만들 때 타입지정이 가능합니다.
변수명:타입명 이렇게 씁니다.
타입으로 쓸 수 있는 것들은 string, number, boolean, bigint, null, undefined,[], {} 등이 있습니다.
let 이름:string = 'kim';
이름 = 123;
타입을 지정해놓으면 타입이 의도치 않게 변경될 경우 에러메세지를 띄워줍니다.
덕분에 타입관련 버그들을 사전에 찾아 없앨 수 있습니다.
let 이름 :string[] = ['kim', 'park']
let 나이 :{ age : number } = { age : number }
array 혹은 object자료는 이렇게 타입지정이 가능합니다.
let 이름 :string | number = 'kim';
이 변수에 여러가지 타입의 데이터가 들어올 수 있다면 | 기호를 이용해 or 연산자를 표현할 수 있습니다. 위 예제는 변수에 숫자 혹은 문자를 집어넣을 수 있게 됩니다.
type nameType = string | number;
let 이름 :nameType = 'kim';
type 키워드를 이용해 타입을 변수처럼 담아서 사용가능합니다.
type NameType = 'kim' | 'park;
let 이름 :NameType = 'kim';
string number 이런 것 뿐만 아니라 나만의 타입을 만들어 사용가능합니다.
저렇게 원하는 글자나 숫자를 입력하면 이름이라는 변수엔 앞으로 'kim'또는 'park'만 들어올 수 있습니다. literal type이라고 부릅니다.
type을 써도 되고, interface를 써도 되고, 마음대로 해도 되는데 프로젝트에서 일관성만 유지하면 됩니다. A에서는 interface를 쓰고, B에서는 type을 쓰고 이런건 지양해야한다는 겁니다.
튜플은 서로 다른 타입을 담을 수 있는 배열입니다. 튜플은 인덱스를 통해 접근해서 가독성이 떨어지므로 인터페이스, 타입 앨리어스(Type Alias)또는 클래스로 대체하여 사용하는 게 좋습니다.
let numberArray: number[] = [1,2,3]; // 배열
let tuple: [boolean, number, string] = [true, 1, 'Ok']; // 튜플
함수의 매개변수 타입과 반환 타입을 함께 지정합니다.
function add(n1: number, n2: number): number {
return n1 + n2;
}
Optional parameter는 반드시 전달해하지 않아도 되는 파라미터입니다.
매개변수 뒤에 물음표(?)와 콜론 기호(:)를 붙인 후 타입을 명시합니다.
타입스크립트가 제공하는 예약어로 특정 파라미터(인자)를 선택적으로
인자를 더 많이 쓰고 싶거나 생략하고 싶을 때 파라미터 뒤에 '?'를 붙인다.
// optional parameter
function printStr(str1: string, str2?: string) {
console.log(str1, str2);
}
printStr('Type', 'Script'); // 출력결과: Type Script
printStr('Type'); // 출력결과: Type undefined
Default parameter는 값을 전달받지 않으면 기본 값을 설정받는 파라미터입니다.
타입을 명시한 후 기본 값을 명시합니다.
// Default parameter
function printStr(str: string = 'Type Script') {
console.log(str);
}
printStr(); // 출력결과: Type Script
Rest parameter는 개수가 유동적인 파라미터입니다. 파라미터를 배열로 정의하면 됩니다.
// Rest parameter
function multiply(...nums: number[]): number {
return nums.reduce((a, b) => a * b);
}
console.log(multiply(1, 2, 3, 4, 5));
배열로 선언한 변수 뒤에 배열 타입을 명시합니다.
const nums: Array<number> = [1, 2, 3];
const script: string[] = ['JavaScript', 'TypeScript'];
함수 내에서 배열의 불변성을 유지하고 싶다면 readonly 키워드를 사용합니다.
function printStr(strs: readonly string[]) {
console.log(strs);
// strs.push('Error');
}
타입 앨리어스는 타입을 직접 정의할 수 있는 기능입니다.
// Object 타입 정의
type Num = {
num: number;
spelling: string,
}
const num1: Num = {
num: 1,
spelling: 'One',
}
console.log(num1.num, num1.spelling);
String Literal Type은 특정 문자열만 지정할 수 있도록 정의합니다.
type TYPESCRIPT = 'TYPESCRIPT';
const typescript: TYPESCRIPT = 'TYPESCRIPT'; // TYPESCRIPT라는 문자열 값만 지정 가능
한 개의 Object로 나타내고 싶다면 interface를 정의하고 사용해야 한다. 이렇게 하면 함수의 정의 부분에서도 각 변수를 object형태로 나타내주어야 한다.
(person.name, person.age, person.gender). interface의 이름은 대문자로 시작해야한다.
호출할 객체를 person으로 정의하고, 그 person의 속성들의 타입을 interface Person으로 정의하였다. 그리고 함수 정의 시에 petson:Person으로 인자를 호출하였다. 즉 interface를 작성하고 그것을 마치 원래 있던 type처럼 사용하는 것이다.
모든 속성값이 필수로 리턴되어야 한다.
만약 함수의 리턴값을 Person 형태로 한다면, 리턴값에 name,age,gender가 모두 포함되어야만 한다. 하나라도 빼고 싶다면, 각 속성값 뒤에 물음표(?)를 붙여주어 선택적인 값으로 처리해주어야 한다.
// JS
function sum(a, b) {
return a+b;
}
sum(10, 20, 30, 40); // 뒤의 숫자는 무시하고 10+20=30 의 결과만 가져온다
// TS
function sum(a: number, b: number) {
return a+b;
}
sum(10, 20, 30, 40); // 숫자 2개의 인자만 와야함으로 오류 발생
interface Person {
name: string;
age: number;
}
type Person = {
name: string;
age: number;
}
var ian: Person = {
name: '이안',
age: 28
}
인터페이스는 확장이 가능하지만 타입 별칭은 확장이 불가능하다.
그러므로 타입 별칭보다는 인터페이스를 사용하는 것을 추천한다.
특정 타입을 '여러 개'쓸 수 있게 해준다.
function logMessage(value: string | number) {
console.log(value);
}
logMessage('Hi');
logMessage(100);
파라미터를 찍으면 해당하는 차입의 API를 자동완성을 통해 쉽게 이용할 수 있다.
var todo: string | number | boolean;
function logMessage(value: string | number) {
if (typeof value === 'number') {
value.toLocaleString();
}
if (typeof value === 'string') {
value.toString();
}
throw new TypeError('value must be string or number');
}
유니온 타입이 인터페이스들을 연결했을 때 '공통된 속성'만 접근이 가능하다.
interface Developer {
name: string;
skill: string;
}
interface Person {
name: string;
age: number;
}
function askSomeone(someone: Developer | Person) {
someone.name //공통 속성만(보장된 속성만) 가능
// 에러가 날 수 있어 타입 검증이 필요하므로 불가능
//someone.skill
//someone.age
}
유니온 타입과 달리 갖고있는 모든 속성의 타입을 '포함'시킨다.
interface Developer {
name: string;
skill: string;
}
interface Person {
name: string;
age: number;
}
function askSomeone(someone: Developer & Person) {
someone.name
someone.skill
someone.age
}
아래의 예시에서 유니온 타입은 Developer 파라미터나 Person 파라미터가 들어가면 되지만,
인터섹션 타입은 Developer, Person 파라미터 속성 모두 합쳐서(name, skill, age) 들어가야 한다.
interface Developer {
name: string;
skill: string;
}
interface Person {
name: string;
age: number;
}
// 유니온 타입
function askSomeone(someone: Developer | Person) {
}
askSomeone({ name: '개발자', skill: '타입스크립트'});
askSomeone({ name: '이안', age: 28 });
// 인터섹션 타입
function askSomeone(someone: Developer & Person) {
}
askSomeone({ name: '이안', age: 28, skill: '타입스크립트'}); // 하나라도 누락시 오류
자바스크립트 객체 타입 = 키와 값을 중괄호로
타입스크립트 객체 타입 = 키와 타입을 중괄호로
그리고 타입스크립트 객체 타입은 쉼표(,)로 속성을 나누는 것이 아니라.
세미콜론(;)으로 나눈다는 것이 차이점입니다.
자바스크립트는 '동적인 타입'
타입스크립트는 '정적인 타입'